Open project in a new tab

I have a project in Google app script content in Index.html and i can open it through a menu with this code, but display in a Modal


function doGet(){

const html = HtmlService.createTemplateFromFile("Index")
.evaluate();
return html;

}


function onOpen() {
  SpreadsheetApp.getUi()
      .createMenu('Options')
      .addItem('Review students', 'openDialog')
      .addToUi();
}

function openDialog() {
  var html = HtmlService.createHtmlOutputFromFile('Index')
  .setHeight(1976)
    .setWidth(1986);
  SpreadsheetApp.getUi() 
      .showModalDialog(html, 'Tittle');
}


How I make for the project open in a new tab and no in a modal?

How can I use react-testing-library to test that a file input shows a preview once a file is selected?

I’m struggling to test a file input component I’ve made to work with react-hook-form.

I’m following the guidance given in the react-testing-library docs.

Here’s the component:

// FileField.tsx

import { ACCEPTED_IMAGE_TYPES } from "@/config"
import Image from "next/image"
import { ChangeEvent, HTMLProps, useState } from "react"
import { useFormContext } from "react-hook-form"

interface Props extends HTMLProps<HTMLInputElement> {
  name: string
}

const FileField = ({ name, ...props }: Props) => {
  const [previewUrl, setPreviewUrl] = useState<string>("")

  const { register } = useFormContext()

  const handleUploadedFile = (e: ChangeEvent<HTMLInputElement>) => {
    const file = e.target?.files?.[0]
    if (file) setPreviewUrl(URL.createObjectURL(file))
  }

  return (
    <div>
      <label className="ds_label" htmlFor="file">
        File
      </label>

      <input
        type="file"
        id="file"
        accept="image/jpg, image/jpeg, image/png"
        {...register(name)}
        onChange={handleUploadedFile}
        data-testid="file-input"
        {...props}
      />

      {previewUrl && <Image width={500} height={500} src={previewUrl} alt="" />} // this is what we're trying to test
    </div>
  )
}

export default FileField

The component works fine in the browser, but I’m having trouble simulating the act of choosing a file, which should trigger a previewUrl to be set and an <Image/> component to be rendered.

Here’s a test that shows the issue:

// FileField.test.tsx

import { render, screen } from "@testing-library/react"
import { useForm, FormProvider } from "react-hook-form"
import userEvent from "@testing-library/user-event"
import FileField from "./FileField"

interface FakeFormProps {
  children: React.ReactElement
}

const FakeForm = ({ children }: FakeFormProps) => {
  const helpers = useForm()

  return <FormProvider {...helpers}>{children}</FormProvider>
}

describe("FileField", () => {
  const user = userEvent.setup()

  it("shows a preview once a file is selected", async () => {
    render(
      <FakeForm>
        <FileField name="bar" />
      </FakeForm>
    )

    await user.upload(
      screen.getByTestId("file-input"),
      new File(["blob"], "hello.png", { type: "image/png" })
    )  // problem seems to be here—this doesn't trigger the same behaviour seen in the browser

    expect(screen.getByRole("img")) // always fails :(
  })
})

I’ve already tried:

  • various combos of act, waitFor and setTimeout to make sure there’s no async weirdness going on
  • swapping out userEvent for the simpler fireEvent
  • a few different ways of creating the fake file to upload

My hypothesis is that the user.upload operation is somehow not doing all the same things that a real user selecting a file would. Eg. not triggering the onChange handler attached to the field, but I’m at a loss for what else to try.

Again—the component works fine, so I’d like to limit any changes to just the tests.

How to combine multer uploads?

I need to be able to upload a single image AND an array of images (both are optional fields on the frontend so I want to keep them separate). My code works if I use one upload or the other. How do I properly combine upload.single('frontImage') and upload.array('files[]')?

router.post(
  '/create',
  upload.single('frontImage').array('files[]'), /// <-- HOW DO I WRITE THIS LINE?
  [check('title').not().isEmpty()],
  flashCardsControllers.createFlashCard
);

vuejs mounted is not waiting for private function to return

Full disclosure, I’m a .NET/C# dev and a complete novice when it comes to javascript. This language is breaking my brain.

I’m trying to get the broswer’s location to feed to a map component that is being created in mounted as part of the vuejs options lifecycle. It correctly calls the private function, but navigator.geolocation.getCurrentPosition returns AFTER mounted finishes, so the map is initialized to a position of 0,0 (my defaults) instead of the correct long/lat. I suspect something should be using async/await but I can’t figure out where or how to get that to work, no matter what I’ve tried. My code is below.

The private function:

function calculateBrowserLocation() {
let location = {
  longitude: 0,
  latitude: 0
}

if ("geolocation" in navigator) {
  navigator.geolocation.getCurrentPosition((position) => {
    console.log(`Inside navigator.getCurrentPositionnlongitude: ${position.coords.longitude}nlatitude: ${position.coords.longitude}`)
    location.longitude = position.coords.longitude
    location.latitude = position.coords.latitude      
  })
}    

console.log(`Inside GetBrowserLocationnlongitude: ${location.longitude}nlatitude: ${location.longitude}`)

return location  }

The export default section:

export default {
setup() {    
  let browserLocation = {
    longitude: 0,
    latitude: 0
  }
  let bearing = 0
  let pitch = 0
  let zoom = 10

  return { browserLocation, bearing, pitch, zoom } 
},

mounted() {
  console.log(`Before GetBrowserLocationnlongitude: ${this.browserLocation.longitude}nlatitude: ${this.browserLocation.longitude}`)

  this.browserLocation = calculateBrowserLocation()

  console.log(`After GetBrowserLocationnlongitude: ${this.browserLocation.longitude}nlatitude: ${this.browserLocation.longitude}`)

  const map = new mapboxgl.Map({
    container: this.$refs.mapContainer,
    style: "mapbox://styles/mapbox/streets-v12",
    center: [this.browserLocation.longitude, this.browserLocation.latitude],
    bearing: this.bearing,
    pitch: this.pitch,
    zoom: this.zoom
  })

  console.log(`After map creationnlongitude: ${this.browserLocation.longitude}nlatitude: ${this.browserLocation.longitude}`)
},

unmounted() {
  this.map.remove()
  this. Map = null
}}

The output of all those console.log statements, which demonstrates the timing issues of all of this looks like:

enter image description here

I suspect it’s something very simple, as these things often are, but I haven’t been able to Google/SO/Reddit my way out of it.

I thank you all in advance.

FloodFill in grid view

I am trying to make a FloodFill function JavaScript this is my html code:

html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>

    <div id="container">
        <div class="container">
            <div class="main-container">
                <div class="left">
                    <div class="tools">
                        <div class="brush tool" >
                            <i class="bi bi-brush-fill"></i>
                        </div>
                        <div class="fill tool">
                            <i class="bi bi-paint-bucket"></i>
                        </div>
                    </div>
                    <div class="rangeSlide">
                        <p><span id="selectedIndex"></span> px</p>
                        <input type="range" id="indexRange" min="0" step="1" value="1">
                    </div>
                </div>
                <div class="pixel-grid"></div>
                <div class="right" id="colorPalette">
                    <!-- <div class="color selected" style="background-color: rgb(0, 0, 0);"></div> -->
                </div>
            </div>
        </div>
    </div>

    <script src="script.js"></script>



</body>
</html>

css:

*{
    margin: 0;;
}
.container {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100vh;
    background-color: rgb(211,211,211);
}

.main-container{
    display: flex;
    box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.2);
    border-radius: 20px;
}


/*---------------------Left--------------------*/
.left{
    background-color: rgb(237,237,237);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    align-items: center;
    border-radius: 20px 0 0 20px;
    width: 50px;
}

.tools{
    /* background-color: rgb(0, 255, 42); */
    border-bottom: 1px solid black;
    height: 100%;
}

.rangeSlide{
    /* background-color: #ff00ff; */
    height: 100%;
}

#indexRange {
    transform: rotate(270deg);
}

.rangeSlide{
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    width: 50px;
}

.rangeSlide p{
    position: relative;
    top: -70px;
}


/*---------------------Left--------------------*/

/*---------------------Right--------------------*/
.right{
    background-color: rgb(237,237,237);
    /* padding: 10px; */
    border-radius: 0 20px 20px 0;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    align-items: center;
    width: 50px;
}

.color{
    border: 1.5px solid rgba(0,0,0,0.2);
    border-radius: 50%;
    height: 1.4rem;
    width: 1.4rem;
    cursor: pointer;
    /* box-sizing: border-box; */
}
/*---------------------Right--------------------*/


/*---------------------Tools--------------------*/
.tools {
    display: flex;
    flex-direction: column;
  }
  
  .tool {
    margin-top: 0.6rem;
    border: 1px solid #cccccc;
    border-radius: 50%;
    height: 1.7rem;
    width: 1.7rem;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
  }

  .tool.selected {
    border-color: rgba(0, 0, 0, 0.45);
    background-color: rgba(0, 0, 0, 0.1);
  }

/*---------------------Tools--------------------*/



.pixel-grid {
    display: grid;
    /* grid-template-columns: repeat(8, 1fr);
    grid-template-rows: repeat(8, 1fr); */
    
    background-color: white;
    padding: 5px;

    
    width: 400px;
    height: 400px;
}

.grid-item {
    /* background-color: white; */
    border: 1px solid rgba(204, 204, 204, 0.3);
}

javascript:


  // Function to check if two colors are the same
  function colorsAreSame(color1, color2) {
    return color1 === color2;
  }


document.addEventListener('DOMContentLoaded', function () {
  console.log('Script loaded and DOM content loaded.');

  const myRange = {'0': 4, '1': 8, '2': 16, '3': 32, '4': 64};

  let selectedColor = 'rgb(0, 0, 0)';
  let isBrushSelected = false;
  let isDrawing = false;
  let isFillSelected = false;


  // Color array
  const colorPalet = [
    'rgb(0, 0, 0)',
    'rgb(255, 0, 0)',
    'rgb(9, 255, 0)',
    'rgb(0, 174, 255)',
    'rgb(255, 0, 255)',
    'rgb(238, 255, 0)',
    'rgb(255, 123, 0)',
    'rgb(255, 255, 255)'
];

 // Get the colorPalette container
 const colorPaletteContainer = document.getElementById('colorPalette');
 


 colorPalet.forEach(color => {
     const colorDiv = document.createElement('div');
     colorDiv.className = 'color';
     colorDiv.style.backgroundColor = color;

     colorDiv.addEventListener('click', function () {
         selectedColor = color;
         setSelectedTool(this);
     });


     colorPaletteContainer.appendChild(colorDiv);
 });





  const indexRangeInput = document.getElementById('indexRange');
  const selectedIndexSpan = document.getElementById('selectedIndex');
  const pixelGridContainer = document.querySelector('.pixel-grid');




  const numberOfItems = Object.keys(myRange).length;
  const rangeMax = parseInt(numberOfItems) - 1;


  indexRangeInput.setAttribute('max',  rangeMax.toString());




  const selectedValue = myRange[indexRangeInput.value];

  selectedIndexSpan.textContent = selectedValue;
  
  createGrid(selectedValue);

  indexRangeInput.addEventListener('input', function () {
    const selectedIndex = parseInt(indexRangeInput.value);


    const selectedValue = myRange[selectedIndex];
 
    selectedIndexSpan.textContent = selectedValue;

    console.log(`Selected Value: ${selectedValue}`);


    createGrid(selectedValue);
  });



  // Create the grid
  function createGrid(value) {
    const rows = value;
    const columns = value;

    pixelGridContainer.innerHTML = '';

    for (let i = 0; i < rows; i++) {
        for (let j = 0; j < columns; j++) {
            const gridItem = document.createElement('div');

            gridItem.className = 'grid-item';

            gridItem.style.backgroundColor = 'white';

            pixelGridContainer.appendChild(gridItem);
        }
    }



    // Set the grid layout styles after creating all the grid items
    pixelGridContainer.style.gridTemplateColumns = `repeat(${columns}, 1fr)`;
    pixelGridContainer.style.gridTemplateRows = `repeat(${rows}, 1fr)`;
  }



  

  // Tool selection
  const tools = document.querySelectorAll('.tool');


  tools.forEach(tool => {
      tool.addEventListener('click', function () {
          isBrushSelected = this.classList.contains('brush');
          isFillSelected = this.classList.contains('fill');
          setSelectedTool(this);
      });
  });


  
  function setSelectedTool(selectedTool) {
    tools.forEach(tool => {
      if (selectedTool.closest('.left')){
        tool.classList.remove('selected');
        tool.style.borderColor = 'rgba(0, 0, 0, 0.3)';
        tool.style.backgroundColor = 'rgba(0, 0, 0, 0)';
      }
    });

    if (selectedTool.closest('.left')){
      selectedTool.classList.add('selected');
      selectedTool.style.borderColor = 'rgba(0, 0, 0, 0.45)';
      selectedTool.style.backgroundColor = 'rgba(0, 0, 0, 0.1)';
    }
}
  
  // Trigger a click event on the brush tool to select it by default
  const brushTool = document.querySelector('.brush');
  brushTool.click();



//color picker
const colors = document.querySelectorAll('.color');

colors.forEach(color => {
    color.addEventListener('click', function () {
        selectedColor = this.style.backgroundColor;
        setSelectedTool(this); // Ensure the brush is selected when choosing a color
    });
});



  //coloring
  pixelGridContainer.addEventListener('mousedown', function (event) {
      if (isBrushSelected || isFillSelected) {
          isDrawing = true;
          if (isBrushSelected) {
              draw(event.target);
          } else if (isFillSelected) {
            floodFill(event.target);
          }
      }
  });

  pixelGridContainer.addEventListener('mousemove', function (event) {
    // if (isDrawing && isBrushSelected) {
    //   draw(event.target);
    // }
    if (isDrawing && (isBrushSelected || isFillSelected)) {
      if (isBrushSelected) {
          draw(event.target);
      } else if (isFillSelected) {
          floodFill(event.target);
      }
  }
});

  pixelGridContainer.addEventListener('mouseup', function () {
      isDrawing = false;
  });
  

// Draw function
  function draw(target) {
      if (target.classList.contains('grid-item') && isBrushSelected) {
          target.style.backgroundColor = selectedColor;
      }
  }







// Flood Fill function







  //Double click del
  pixelGridContainer.addEventListener('dblclick', function (event) {
      if (isBrushSelected) {
          if (event.target.classList.contains('grid-item')) {
              event.target.style.backgroundColor = '';
          }
      }
  });

});

I am trying to make a FloodFill function for a pixel grid canvas i tried multiple ways and still cant figure it out does anyone know how make this function and explain how its done? I tried to check the surrounding grid item and check there element.style since the style is done inline but still nothing works with me. I even tried dfs and bfs.

How to view console messages from specific js files in firefox

I have two js files that interact with each other and I only need to see errors and logs from those two js files while debugging. Everything else is distracting.
In chrome, I can right click on the script file names in the console log and click “hide messages from x.js”, but firefox doesn’t seem to have that.

Also, using the negative sign only works on one word.

Lastly, In the filter bar. Regex doesn’t seem to work for excluding words. Only including.

What is the best solution for only seeing messages from the files I want?

How to post a task in selected column of imported jsonData node.js express

i am a beginner in javascript and therefore would need some help with this task.

I have a columns.json file that is filled with tasks, which I have already Imported with

const jsonData = require('./data/columns.json');

now I have to implement a post request which posts a new task to a column in the Json file. The Number in the request Bdoy specifies the column to which the task should be added. The response is the newly calculated id of that task.
the request body looks like this:

{
"column": Number,
"title": String,
"text": String, 
"taskTags: Array[String]
} 

The Statuscode is 201.

Response – Body:

{ 
"id": String
}

I have successfully implemented the function which calculates the new ID of the Task.
For the POST request I have tried this:

app.post('/api/tasks', (req, res) => {
            body = '';
            
            req.on('data', chunk => {
                body += chunk.toString();
            });
            
            req.on('end', () => {
                if(body.length > 0) {
                    
                    console.log(body);
                    let newData = qs.parse(body);
                    console.log(newData);
                    
                    
                    if( !newData.title || !newData.text || isNaN(newData.column)) {
                        res.writeHead(400);
                        res.end();
                    } else {
                        let newId = calculateInitialTaskIdCounter();
                       let newTask = {
                            id: newId,
                            column: newData.column,
                            title: newData.title,
                            text: newData.text,
                            taskTags: newData.taskTags || []
                        };
                        const target = jsonData.find(column => column.id == newData.column);
                        if (target) {
                          target.tasks.push(newTask);
                        
                        res.writeHead(201, {'Content-Type': 'application/json'});
                        res.end(JSON.stringify({id: newId}));
                      } else  {       
                
                    res.writeHead(400);
                    res.end();
                  }
                }
            }else {
              res.writeHead(400);
      res.end();
     }
 });
            
}); 

but it sais Cannot GET /api/tasks.

What am I doing wrong?

Toggling one element’s display that has a certain class when clicking on the button “corresponding” to it using vanilla javascript

HTML:

{% for i in range(l) %}
  <button class="t_b_show" onclick="func_show(this);"> Show this list</button>
  <div class="toggle_div" hidden="true">  
    <ul>
      <li> {{list1[i]["name"]}}</li>
      <li> {{list1[i]["note"]}}</li>
    </ul>
  </div>
  <button class="t_b_hide" hidden="true" onclick="func_hide(this);">Hide this list</button>
{% endfor %}

javascript:

function func_show(theButton) {
  subNoteDivs = document.getElementsByClassName('toggle_div');
  showButtons = document.getElementsByClassName('t_b_show');
  hideButtons = document.getElementsByClassName('t_b_hide');
  thisElement = theButton;
  console.log(thisElement);//shows the clicked element in the console, meaning the element itself                                         passes to the function
  
  if(showButtons.length > 0) {
    for (let i = 0; i < showButtons.length; i++){
      if(showButtons[i] == thisElement){
        let j = i;
        i = showButtons.length;
      }
    }
  }
  console.log(j);
  subNoteDivs[j].setAttribute('hidden', false);
  hideButtons[j].setAttribute('hidden', false);
  showButtons[j].setAttribute('hidden', true);
}


function toggle_func_hide(theButton) {
  subNoteDivs = document.getElementsByClassName('toggle_div');
  showButtons = document.getElementsByClassName('t_b_show');
  hideButtons = document.getElementsByClassName('t_b_hide');
  thisElement = theButton;
  console.log(thisElement);//shows the clicked element in the console, meaning the element itself                                         passes to the fuction
  if (hideButtons.length > 0){
    for (let i = 0; i < hideButtons.length; i++){
      if(hideButtons[i] == thisElement){
        let j = i;
        i = hideButtons.length;
      }
    }
  }
  console.log(j);
  subNoteDivs[j].setAttribute('hidden', true);
  hideButtons[j].setAttribute('hidden', true);
  showButtons[j].setAttribute('hidden', false);
}

Short explanation about the code for context:

I am trying to rite an app that allows the user to write notes on subjects, the subjects are added by the user and tables on them are created to which they can add notes on the subjects.

The program works fine but displaying all the tables makes the page look hideous, and so I want to give the user the option to show the tables they want by clicking on a button “corresponding” to each table,
and hide them by clicking on a button as well.
I can’t use ids because the number of elements is dynamic and therefore I can only set classes which copies of the same elements created with the tables have.
And so I tried writing both functions above: By clicking on a button next to a table, a function is called, which after finding out the index of the button clicked within the HTMLCollection of same class elements, changes the attributes of the elements in the functions above that are in the same index as the button clicked in their respective HTMLCollection of the elements with the same class.

The problems I faced:

One problem is, I don’t know how to make javascript check which index the clicked button is, I tried the above code but it always gives the error that j is undefined meaning the comparison in the if statement is not the correct way of checking which index the clicked button is in.
I searched for a another way to check but didn’t find how the correct comparison is done.
I also tried using the “array.indexof(theElement)” method but it gives an error “indexOf is not a function”.

A second one i encountered before, unrelated to the above problem is “setAttribute is not a function”, too.

I tried searching for a fix all day but couldn’t solve it, please help. And if there is another way to acheive the goal, that would also work.

In the code above I used a list instead of a table for simplicity’s sake, as the code above is only similar to the code I am working on

Also I am very new to programming and this is my first question so sorry if the problem turns out to be silly or the the problem is poorly clarified.

Transform a blurhash to grayscale

Does anyone have an idea of how we can implement an efficient algorithm (js/ts) that given a blurhash string returns the equivalent (even of reduced quality) but in grayscale?

I need it because I use blurhashes as image holders, but in a part of my application I need to display images in black and white. Thanks in advance

Intuit (Quickbooks) API Upload Image as an attachable to an Item (product) NodeJs

I’m using the Quickbooks API with the NodeJS SDK (oauth-jsclient) and I’m having issues trying to figure out how to upload an image to an Inventory Item. Per documentation (docs)it says to make a multipart/form-data post request to the endpoint https://sandbox-quickbooks.api.intuit.com/v3/company/${company_id}/upload?minorversion=70.

I’m doing all that and I’m also using the form-data library to handle the multipart/form-data to attach the image file. The issue I’m having is that I get an error response from the API saying Content length missing in request","Detail":"We cannot find the content-length header in the request.","code":"6020"}

Here is the relevant part of my code:

try {
  if (images?.length) {
    const image = images[0];
    const imageFile = fs.createReadStream(image.rawInfo.path);
    
    const form = new FormData();

    form.append('file_content_01', imageFile, {
      filename: image.rawInfo.filename,
      contentType: image.rawInfo.mimetype,
    });

    form.append(
      'file_metadata_01',
      JSON.stringify({
        AttachableRef: [
          {
            EntityRef: { type: 'Item', value: newQBProduct.Id },
          },
        ],
        ContentType: image.rawInfo.mimetype,
        FileName: image.rawInfo.filename,
      }),
      {
        contentType: 'application/json',
        filename: 'file_metadata_01',
      }
    );
    
    console.log({ formHeader: form.getHeaders() });
    
    const imageResponse = await qbClient.makeApiCall({
      url: `${process.env.QB_API_URL}/v3/company/${process.env.QB_COMPANY_ID}/upload?minorversion=69`,
      method: 'POST',
      headers: {
        ...form.getHeaders(),
      },
      body: form,
    });
  }
} catch (error) {
  console.log({ ERROR_UPLOADING_IMAGE: error });
}

If I console log the headers this is what I get:

{
  formHeader: {
    'content-type': 'multipart/form-data; boundary=--------------------------348255206805762341115729'
  }
}

Any ideas what I’m doing wrong? any help would be greatly appreciated.

Custom web Component forced render

import ComponentFactoryInstance from "../../ui/componentFactory";
import notifier from "../../utils/notifier";


export default class AppUiComponent {

  ComponentFactory: any

  constructor() {

  }

  static build() {

    const appRoot = document.createElement('div');

    const style = document.createElement("style");

    const toolBar = ComponentFactoryInstance.create('girovo-tool-bar');

    ComponentFactoryInstance.create('girovo-menu-bar');

    const toolBarEditingPan = document.createElement("div");

    toolBarEditingPan.setAttribute("style", "display:flex;");

    const _toolBar = toolBarEditingPan.appendChild(toolBar)

    notifier.subscribe("build_tool_ui", data => {

      (_toolBar as iToolBar).buildTool({icon: data!.icon});

      //                    or
      // (toolBar as iToolBar).buildTool({icon: data!.icon});
      
    });
    
    toolBarEditingPan.innerHTML += `<div style="flex-grow:1;" class="editing-pan" ></div>`;

    style.textContent = `
          :host {
            display: inline-flex;
            border-radius: 2px;
            padding: 1px;
            background-color: lightgrey;
            width: 37px;
            height: 30px;
      }`;

      appRoot.innerHTML = `<girovo-menu-bar></girovo-menu-bar>`;

      appRoot.appendChild(toolBarEditingPan)

      appRoot.appendChild(style);

      return appRoot

  }

}

The provided code defines a class that includes a build method. Within this method, a component factory class is employed to generate a new instance of a specific custom web component. This instance is then appended to the DOM, and concurrently, modifications are applied to the custom component by adding children to it.

However, there is an issue as it appears challenging to obtain the precise reference to the created component. While appending a child does not reflect in the DOM, console logging reveals the component. Furthermore, the logged custom component possesses a distinct _id property compared to the component rendered in the DOM. This inconsistency is observed when using a reference to the component after it has been appended to the DOM, making it seem like a different instance is being worked with. The concern is how to ensure the utilization of the same instance.

To address this challenge, it is essential to ensure that the reference to the custom component is correctly captured after it has been appended to the DOM. Confirm that the reference used for subsequent manipulations, such as adding children, corresponds to the instance actually rendered in the DOM. Additionally, ensure that any asynchronous operations or updates to the component’s state are properly handled to maintain synchronization between the instance and its representation in the DOM. for clarification this my code for the custom component

import ComponentFactoryInstance from "./componentFactory";
import idGenerator from "../utils/idGenerator";




export default class ToolBar extends HTMLElement {

  shadow: ShadowRoot
  _id: string | void
  parent: any

  constructor() {

    super();

    this._id = idGenerator().next().value;
    
    this.shadow = this.attachShadow({ mode: "open" });

  }

  connectedCallback() {

    if (this.parentNode) {
      this.parent = this.parentNode;
    }

    const style = document.createElement("style");

    const ele = document.createElement('div')

    style.textContent = `
            :host {
              display: flex;
              flex-direction: column;
              height: 500px;
              background-color: lightgrey;
    }`;

    this.shadow.appendChild(style);

  }

  render() {

    // console.log(this.shadow.children, "00000000000")
    const removedChilds = [];

    // Clear existing children in the DOM
    while (this.shadow.firstChild) {

      removedChilds.push(this.shadow.removeChild(this.shadow.firstChild));

    }

    // Append each child to the DOM
    removedChilds.forEach((child) => {

      this.shadow.appendChild(child);

    });

  }

  buildTool(toolData: Record<string, any>){

    const tool = ComponentFactoryInstance.create("girovo-toolicon", {
      width: "25px",
      height: "25px",
      src: toolData.icon
    })

    this.shadow.appendChild(tool)

    this.render()

  }

  
} ```

when logging the component inside the connectedCallback method 

When to use Nested Objects [closed]

I’m currently trying to better my JavaScript skills and I’m watching “JavaScript Full Course – Beginner to Pro – Part 1” by SuperSimpleDev and while watching it, I got confused about nested objects I tried looking it up but can only find sites that cover what they are. When exactly would you need to use a nested object? Anything will help, thanks.

I just needed to add code to ask the question. This is the example he used to show what a nested object looked like. BUT if this is enough to explain why “rating” is a nested object, that would work as the explanation.

  const product2 = {
    name: 'shirt',
    ['delivery-time']: '1 day',
    rating: {
      stars: 4.5,
      ratings: 87
    }
  };

(Ajax) Converting from px to other units for a pop-up window

I have this code for creating an in-window pop up that depends on a specified width in the HTML:

$(document).ready(function() {

    //

//When you click on a link with class of poplight and the href starts with a # 

$('a.poplight[href^=#]').click(function() {
    var popID = $(this).attr('rel'); //Get Popup Name
    var popURL = $(this).attr('href'); //Get Popup href to define size

    //Pull Query & Variables from href URL
    var query= popURL.split('?');
    var dim= query[1].split('&');
    var popWidth = dim[0].split('=')[1]; //Gets the first query string value

    //Fade in the Popup and add close buttonpx
    $('#' + popID).fadeIn().css({ 'width': Number( popWidth ) }).prepend('<a href="#" class="close">Close</a>');

    //Define margin for center alignment (vertical   horizontal) - we add 50px to the height/width to accomodate for the padding  and border width defined in the css
    var popMargTop = ($('#' + popID).height()) / 2;
    var popMargLeft = ($('#' + popID).width() + 80) / 2;

    //Apply Margin to Popup
    $('#' + popID).css({
        'margin-top' : -popMargTop,
        'margin-left' : -popMargLeft
    });

    //Fade in Background
    $('body').append('<div id="fade"></div>'); //Add the fade layer to bottom of the body tag.
    $('#fade').css({'filter' : 'alpha(opacity=80)'}).fadeIn(); //Fade in the fade layer - .css({'filter' : 'alpha(opacity=80)'}) is used to fix the IE Bug on fading transparencies 
    return false;
});

//Close Popups and Fade Layer

$('a.close, #fade').live('click', function() { //When clicking on the close or fade layer...
    $('#fade , .popup_block').fadeOut(function() {
    $('#fade, a.close').remove();  //fade them both out
    });
    return false;
});

});

...

<a href="#?w=900" rel="about" class="poplight">about</a></b> / <a href="#?w=700" rel="writing" class="poplight">writer</a> / <a href="#?w=700" rel="code" class="poplight">coder</a>

...

<div id="about" class="popup_block"></div>
<div id="writing" class="popup_block"></div>
<div id="code" class="popup_block"></div>

That automatically and only accepts px units of measurement, not anything else. I want to make the site responsive so I’d like to be able to control it in em/vh/vw/% (depending) but I don’t really know any Ajax so I don’t know how.

Any help would be great!

I did try typing it in the link but it didn’t give the div any width at all.

FastAPI stuck on Waiting for application startup

I’m trying to create a web app using FastAPI, to show weather and time and Bitcoin price and etc. This is the Python code (I obviously replace the OPENWEATHERMAP_API_KEY and other stuff):

from fastapi import FastAPI, Request, WebSocket, WebSocketDisconnect, BackgroundTasks
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
import requests
import asyncio

app = FastAPI()

# Templates
templates = Jinja2Templates(directory="templates")

# Static files (like CSS and JS)
app.mount("/static", StaticFiles(directory="static"), name="static")

# API key for OpenWeatherMap (replace with your own)
OPENWEATHERMAP_API_KEY = "YOUR_OPENWEATHERMAP_API_KEY"

# Background task to update Bitcoin price every minute
async def update_bitcoin_price(background_tasks: BackgroundTasks):
    while True:
        await asyncio.sleep(60)
        bitcoin_price = get_bitcoin_price()
        background_tasks.add_task(update_data, "bitcoinPrice", f"Bitcoin Price: €{bitcoin_price}")

# Background task to update weather information every 5 minutes
async def update_weather_info(background_tasks: BackgroundTasks):
    while True:
        await asyncio.sleep(300)
        weather_info = get_weather_info()
        background_tasks.add_task(update_data, "weatherInfo", weather_info)

# Background task to update text file contents every 4 hours
async def update_file_contents(background_tasks: BackgroundTasks):
    while True:
        await asyncio.sleep(14400)
        file_contents = get_file_contents()
        background_tasks.add_task(update_data, "fileContents", f"Text File Contents: {file_contents}")

# Function to fetch Bitcoin price from CoinGecko API
def get_bitcoin_price():
    response = requests.get('https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=eur')
    response.raise_for_status()
    data = response.json()
    return data["bitcoin"]["eur"]

# Function to fetch weather information from OpenWeatherMap API
def get_weather_info():
    city = "YOUR_CITY"  # Replace with the city of your choice
    weather_endpoint = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={OPENWEATHERMAP_API_KEY}&units=metric"
    response = requests.get(weather_endpoint)
    response.raise_for_status()
    data = response.json()
    temperature = data["main"]["temp"]
    weather_description = data["weather"][0]["description"]
    return f"Weather: {weather_description}, Temperature: {temperature}°C"

# Function to fetch text file contents
def get_file_contents():
    try:
        with open("your_text_file.txt", "r", encoding="utf-8") as file:
            return file.read()
    except FileNotFoundError:
        return "Text file not found"

# Function to update data on the web page
def update_data(data_id: str, new_data: str):
    sockets_to_update = list(app.state.websockets)
    for socket in sockets_to_update:
        socket["background_tasks"].add_task(emit_data, socket["websocket"], data_id, new_data)

# Function to emit data to connected clients
async def emit_data(websocket, data_id: str, new_data: str):
    await websocket.send_text(f'{{"id": "{data_id}", "data": "{new_data}"}}')

# Route to handle the WebSocket connection
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    app.state.websockets.add({"websocket": websocket, "background_tasks": BackgroundTasks()})
    try:
        while True:
            data = await websocket.receive_text()
    except WebSocketDisconnect:
        app.state.websockets.remove({"websocket": websocket, "background_tasks": BackgroundTasks()})

# Route to render the HTML page
@app.get("/", response_class=HTMLResponse)
async def read_item(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

# Start background tasks
@app.on_event("startup")
async def startup_event():
    app.websockets = set()
    background_tasks = BackgroundTasks()
    background_tasks.add_task(update_bitcoin_price)
    background_tasks.add_task(update_weather_info)
    background_tasks.add_task(update_file_contents)
    app.add_event_handler("startup", startup_event)

# Serve the app using Uvicorn
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)

And this is the HTML file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>FastAPI Web App</title>
    <style>
        body {
            background-color: black;
            color: green;
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            text-align: center;
        }

        #time {
            font-size: 24px;
            margin-top: 20px;
        }

        #bitcoinPrice {
            font-size: 18px;
            margin-top: 10px;
        }

        #additionalText {
            font-size: 20px;
            font-family: 'Times New Roman', Times, serif;
            margin-top: 15px;
        }

        #weatherInfo {
            font-size: 16px;
            margin-top: 10px;
        }

        #fileContents {
            font-size: 16px;
            margin-top: 10px;
        }
    </style>
</head>
<body>
    <h1>Hello, this is a FastAPI web app with live time, Bitcoin price, weather information, and text file contents!</h1>
    <p>This is a simple web app with styling, live time, live Bitcoin price in euros, weather information, and text file contents using FastAPI.</p>

    <div id="time"></div>
    <div id="bitcoinPrice"></div>
    <div id="weatherInfo"></div>
    <div id="fileContents"></div>

    <script>
        // WebSocket connection
        const socket = new WebSocket("ws://127.0.0.1:8000/ws");

        // Function to update data on the web page
        function updateData(data) {
            const element = document.getElementById(data.id);
            if (element) {
                element.innerHTML = data.data;
            }
        }

        // Event listener for WebSocket messages
        socket.addEventListener("message", (event) => {
            const data = JSON.parse(event.data);
            updateData(data);
        });
    </script>
</body>
</html>

When I run the app (using uvicorn main:app --reload) I get this in the console:

INFO:     Will watch for changes in these directories: ['C:\Users...']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [14632] using WatchFiles              
INFO:     Started server process [9072]
INFO:     Waiting for application startup.

And that’s it. Nothing happens. And if Visit http://127.0.0.1:8000, I get this error:

This site can’t be reached
127.0.0.1 refused to connect.

What am I doing wrong?

Using GTM to pull form submission data

I hope somebody can help me here.

Little background.

I have a website I built using squarespace. I have a form that people will submit with their info when they want a quote such as first name/lastname/email/phone/address etc. I want to pull this data and send it to facebook via GTM using some javascript.

Inside GTM, I created several variables to target this form submission data. I’m able to successfully retrieve the First Name + Last Name, but no other variables are returning, all say Undefined.

I can retrieve the first/last name using “return document.getElementsByName” — If I right click my form and Inspect, I can see the First Name is as follows: <input aria-invalid="false" aria-required="true" autocomplete="given-name" class="MUomU4fr3iSZrhBNTmN0 exokPtqDa3qLy42TT3gA" id="name-yui_3_17_2_1_1553888888520_3744-fname-field" **name="fname"** type="text" value="">

Here is the GTM variable I created to target the first name:

function(){

return document.getElementsByName(“fname”)[0] ? document.getElementsByName(“fname”)[0].value : “”;

}

This works perfectly.

However, the email/phone/address don’t have a specified “name” but they do have unique “ID”. Here is what it shows when I right click->inspect for the email:

<input aria-invalid="false" aria-required="true" autocomplete="false" class="MUomU4fr3iSZrhBNTmN0 exokPtqDa3qLy42TT3gA" **id="email-yui_3_17_2_1_1553888888520_3745-field"** placeholder="" type="email" value="">

Here is the variable I used to target the data that didn’t have a unique “Name”. I used

“return document.getElementById”

function(){

return document.getElementById(“email-yui_3_17_2_1_1553888888520_3745”)[0] ? document.getElementById(“email-yui_3_17_2_1_1553888888520_3745”)[0].value : “”;

}

Instead of using the name, i tried using ID but returns undefined.