ESLint Prettier: Parsing error: Unexpected token with

I am fairly new to ESLint, Prettier, and Babel; still learning how they work together. I am using Visual Studio Code 1.96.4, with ESLint and Prettier extensions.

In one of my javascript files, I have an import statement with a type assertion. For example:

import * as manifest from './package.json' with { type: 'json' };
                                           ~~~~

My IDE is telling me that ESLint has an issue with the above import statement:

Parsing error: Unexpected token with | eslint

I have an eslint.config.js file, which exports an eslint.Linter.Config array that specifies my own config object (which has language options and rules), followed by a recommended config from @eslint/js, and the ESLint Prettier plugin recommended config.

import pluginJs from '@eslint/js';
import eslintPluginPrettier from 'eslint-plugin-prettier/recommended';
import globals from 'globals';

/** @type {import('eslint').Linter.Config[]} */
export default [
  {
    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.jest
      },
      ecmaVersion: 2024,
      sourceType: 'module'
    },
    rules: {
      ...
    }
  },
  pluginJs.configs.recommended,
  eslintPluginPrettier    // <-- Removing this fixes the problem, but then am I still running Prettier at lint-time?
];

These are the installed packages that (I think?) are relevant:

"devDependencies": {
  "@babel/core": "^7.26.0",
  "@babel/eslint-parser": "^7.26.5",
  "@babel/plugin-syntax-import-assertions": "^7.26.0",
  ...
  "@eslint/eslintrc": "^3.2.0",
  "@eslint/js": "^9.18.0",
  ...
  "eslint": "^9.18.0",
  "eslint-config-prettier": "^10.0.1",
  "eslint-plugin-prettier": "^5.2.3",
  ...
  "prettier": "^3.4.2",
  ...
},

I also have a .prettierrc file that is a simple JSON object with only rules in it, no plugins or anything. And I don’t know if .babelrc has anything to do with this?

How can I make the IDE error go away, while still enforcing both ESLint and Prettier rules?

Catching errors from async function in try..catch block outside of async function

So I’m doing a tutorial which contains a part about asynchronous JavaScript. I feel like I have it down pretty good, but it includes this section which I feel like is wrong for catching errors?

async function myFunction {
  // ...
  await someObject.methodThatReturnsPromise();
  // ...
  await aFunctionThatReturnsPromise();
  // ...
}

try {
  // ...
  myFunction();
  // ...
} catch (e) {
 // error handling code
}

This is the explanation it gives.

You can see how this works in the example below. myFunction() is an
asynchronous function that is called within a try…catch block. When
myFunction() is run, code execution is paused at
methodThatReturnsPromise() until the promise resolves, at which point
the code continues to aFunctionThatReturnsPromise() and waits again.
The code in the catch block runs if an error is thrown in the
asynchronous function, and this will happen if the promise returned by
either of the methods is rejected.

My understanding is this is all incorrect? To catch errors, either put the try...catch block inside myFunction(), or catch the errors the when calling myFunction() in the global context with

myFunction().catch((error) => console.log(error));

JS parser and short-circuited arrow function

Why does the JS parser require grouping parens after an (empty) arrow-function short-circuit?

Seems like the arrow-function syntax should be detected as an irreducible token.

This code:

( someFunc || ()=>{} )()

Generates a syntax error:

Uncaught SyntaxError: Malformed arrow function parameter list

The fix is to add grouping parens, but I don’t understand why:

( someFunc || (()=>{}) )()

I’d also be curious to see what code the parser is seeing this as. In other words, what code would you need to write to generate that exact error. It’s not doing a lookahead, clearly, so it’s choking somewhere between the || and the closing grouping paren (antepenultimate char).

Optimizing availability check for a booking system

I’m working on a resource booking system and need advice on optimizing my logic for checking resource availability. The current implementation works but feels inefficient since it performs unnecessary checks.

Here’s the scenario:

  1. I have a list of resources (e.g., devices, rooms, or any bookable item) stored in resourceList.
  2. Each resource can have multiple bookings, stored in a bookingList.
  3. When a booking request comes in, I need to check if the requested dates overlap with any existing bookings for that resource. If the resource is available, I add it to the list of confirmed bookings. Each booking has a start date and end date.

Here’s my current code:

// Sample resource list
const resourceList = [
  { resourceId: "R1", status: "Available" },
  { resourceId: "R2", status: "Booked" },
  { resourceId: "R3", status: "Booked" }
];

// Sample booking list
const bookingList = [
  { resourceId: "R2", startDate: "2025-01-10", endDate: "2025-01-15" },
  { resourceId: "R2", startDate: "2025-01-20", endDate: "2025-01-25" },
  { resourceId: "R3", startDate: "2025-01-12", endDate: "2025-01-18" }
];

// Requested dates
const startDate = new Date("2025-01-15");
const endDate = new Date("2025-01-19");

let availableResources = [];
let newBookings = [];
const requiredResources = 1; // Example: Only need 1 resource

for (let resource of resourceList) {
  if (resource.status === "Booked") {
    const resourceBookings = bookingList.filter(
      booking => booking.resourceId === resource.resourceId
    );

    // Check if the resource is available for the requested dates
    const isAvailable = resourceBookings.every(booking => {
      const existingStart = new Date(booking.startDate);
      const existingEnd = new Date(booking.endDate);

      return endDate < existingStart || startDate > existingEnd;
    });

    // Add resource if available and limit not met
    if (isAvailable && availableResources.length < requiredResources) {
      availableResources.push(resource.resourceId);
      newBookings.push({
        resourceId: resource.resourceId,
        startDate: startDate.toISOString().split("T")[0],
        endDate: endDate.toISOString().split("T")[0]
      });
    }
  }
}

My Concerns:

  • Unnecessary checks: I feel like checking each booking should not be the way and there is a better more efficient way to check only a subset of the booking?
  • Performance issues: As the number of resources and bookings grows, this approach might not scale well.

If you’ve tackled a similar problem or have any ideas, I’d love to hear them!

Thank you in advance for your suggestions.

No clues given as to why this Digraph isn’t rendering in my svg

I have the following function:

export async function drawTechTree(techData, svgElement) {
    let graphDef = "digraph TechTree {n";
    graphDef += 'node [style="filled", color="black", fontcolor="white", fillcolor="black", fontname="Arial"];n';

    for (const [key, value] of Object.entries(techData)) {
        const price = value.price || "Unknown";
        const label = `<b>${key}</b><br/>Price: ${price}`;
        graphDef += `${key} [label=<${label}> shape="box"];n`;
    }

    for (const [key, value] of Object.entries(techData)) {
        const appearsAt = value.appearsAt || [];
        if (appearsAt.length > 1) {
            for (let i = 1; i < appearsAt.length; i++) {
                const prereq = appearsAt[i];
                if (prereq) {
                    graphDef += `${prereq} -> ${key};n`;
                }
            }
        }
    }

    graphDef += "}";

    console.log("Graph definition:", graphDef);

    try {
        console.log("Rendering graph...");
        await new Promise((resolve, reject) => {
            d3.select(svgElement)
                .graphviz()
                .zoom(false)
                .renderDot(graphDef)
                .on("end", () => {
                    console.log("Graph rendered successfully");
                    resolve();
                })
                .on("error", (err) => {
                    console.error("Error while rendering the graph:", err);
                    reject(err);
                });
        });
    } catch (error) {
        console.error("An error occurred during graph rendering:", error);
    }
}

I am passing in:

    fetch('./resources/techData.json')
    .then((response) => response.json())
    .then((techData) => {
        drawTechTree(techData, '#techTreeSvg');
    })
    .catch((error) => console.error('Error loading tech data:', error));

This gives graphDef have a perfectly formed DOT string that I can render in other online services that render these in svg’s.

However that is where it all goes wrong.

.renderDot(graphDef) – if I debug through this it gives no clues as to what is happening, but it is not rendering in the specified element that is for sure.

The only console output in this function is related to web workers and I dont think this will affect the render. In fact I tried passing in 'digraph {a -> b}' and that didn’t render neither. The svg is in the DOM and it is with the correct id and I can see it in my web page.

So have you got any advice for me, anything missing from the code? Thanks for reading.

Just to mention I have tried with and without the Promise I included in this snippet. None of the .on() provide anything useful and the .on("end"...) never triggers.

Neural network XOR problem converging to 0.5

I’m working on coding up a neural network from scratch into js, and have implemented the following:

class Network{
constructor(layerSizes, activation){
    this.activation = activation[0]
    this.activationPrime = activation[1]
    this.inverseActivation = activation[2]
    this.numLayers = layerSizes.length
    this.layerSizes = layerSizes
    this.layers = []
    this.state = []
    this.outputs = []
    this.train = false
    for (let i=0; i<this.numLayers; i++){
        var nodes = Array(layerSizes[i])
        var weightsAndBiases = [Array(layerSizes[i-1]).fill(random(0, 1))]
        weightsAndBiases.push(0)
        nodes.fill(weightsAndBiases)
        this.layers.push(nodes)
    }
}

drawNetwork(){ // visualise the network
    for (let i=0; i<this.numLayers; i++){ // iter over layers
        for (let j=0; j<this.layers[i].length; j++){ // iter over nodes
            let coords = transformCoords([i,j], [this.numLayers, this.layers[i].length], [10, 10])
            drawCircle(coords[0], coords[1], 10, colourScale(this.state[i][j], 1, [255,255,255], [22,22,22]), true) // drawing points
            if (i != 0){ // drawing lines
                for (let k=0; k<this.layers[i][j][0].length; k++){
                    let startingCoords = coords
                    let endingCoords = transformCoords([i-1, k], [this.numLayers, this.layers[i-1].length], [10, 10])
                    drawLine(startingCoords[0], startingCoords[1], endingCoords[0], endingCoords[1], colourScale(this.layers[i][j][0][k], 1, [255,255,255], [22,22,22]))
                }
            }
        }
    }        
}

parse(inputs){ // determines the state of the network from given inputs
    this.state = [inputs]
    for (let i=1; i<this.numLayers; i++){
        this.state.push([])
        for (let j=0; j<this.layerSizes[i]; j++){
            var nodeTotal = dot(this.layers[i][j][0], this.state[i-1]) + this.layers[i][j][1]
            nodeTotal = this.activation(nodeTotal)
            this.state[i].push(nodeTotal)
        }
    }
    this.outputs = this.state[this.numLayers-1]
}

cost(inputs, desiredOutputs){
    this.parse(inputs)
    let outputs = this.state[this.numLayers-1]
    let c = []
    for (let i=0; i<outputs.length; i++){
        c.push((outputs[i]-desiredOutputs[i])**2)
    }
    return c
}

run(inputs, desiredOutputs, learningRate){ // changes the weights and biases with respect to the cost function
    let rate = learningRate/inputs.length
    if (this.train){

        let newLayers = JSON.parse(JSON.stringify(this.layers))

        for (let p=0; p<inputs.length; p++){
            // console.log(p*100/inputs.length);
            
            let originalCost = this.cost(inputs[p], desiredOutputs[p])
            let deltas = Array(this.numLayers).fill([])

            deltas[this.numLayers-1] = Array(this.layerSizes[this.numLayers-1]).fill(0)
    
            for (let i=0; i<this.layerSizes[this.numLayers-1]; i++){ // iterate over final nodes and find final deltas
                let dCostdOut = 2*(this.state[this.numLayers-1][i] - desiredOutputs[p][i])
                let dOutdActivation = this.activationPrime(this.inverseActivation(this.state[this.numLayers-1][i]))
    
                deltas[this.numLayers-1][i] = dCostdOut * dOutdActivation
                
                let dCostdBias = deltas[this.numLayers-1][i]
    
                for (let j=0; j<this.layerSizes[this.numLayers-2]; j++){ // iterate over weights of final nodes
                    let dCostdWeight = this.layers[this.numLayers-1][i][0][j] * this.state[this.numLayers-2][j] * deltas[this.numLayers-1][i]
                    newLayers[this.numLayers-1][i][0][j] -= dCostdWeight * rate
                }
    
                newLayers[this.numLayers-1][i][1] -= dCostdBias * rate
            }
    
            for (let i=this.numLayers-2; i>=0; i--){ // inverse layer iter
                deltas[i] = Array(this.layerSizes[i]).fill(0)
                
                for (let j=0; j<this.layerSizes[i]; j++){ // iterate over the current layer's nodes
    
                    for (let k=0; k<this.layerSizes[i+1]; k++){ // iterate over the next layer's nodes to get this layer's deltas
                        deltas[i][j] += this.state[i+1][k] * this.layers[i+1][k][0][j]
                    }
                    deltas[i][j] *= this.activationPrime(this.inverseActivation(this.state[i][j]))
    
                    let dCostdBias = deltas[i][j]
    
                    for (let k=0; k<this.layerSizes[i-1]; k++){ // iterate over previous layer's weights
                        let dCostdWeight = this.layers[i][j][0][k] * this.state[i-1][k] * deltas[i][j]
                        newLayers[i][j][0][k] -= dCostdWeight * rate
                    }
    
                    newLayers[i][j][1] -= dCostdBias * rate
                }
            }
        }
        
        this.layers = newLayers
        this.drawNetwork()
    } else {
        this.parse(inputs[0])
    }
}

}

let inputs = [
    [0, 0],  // Input 1
    [0, 1],  // Input 2
    [1, 0],  // Input 3
    [1, 1],  // Input 4
];

let desiredOutputs = [
    [0],  // Output for Input 1
    [1],  // Output for Input 2
    [1],  // Output for Input 3
    [0],  // Output for Input 4
];

let training = false

setInterval(() => {render();  }, 1)
function render(){
    if (training){
        net.train = true
        net.run(inputs, desiredOutputs, 0.35)
        net.train = false
    }
}

When I set training = true, and then disable it after some time, I find that all the outputs for the inputs are ~0.5. I know that this is a common error with the XOR problem and neural networks, but I have made some internet-found tweaks to no avail. Is there an issue in my logic for the backpropagation step somewhere? I fear that there may be, I’m not quite sure about it.

Specifically, I have attempted changing the activation function to tanh, changing the network structure and number of layers, letting the network train for longer, and increasing the learning rate. I have also been reviewing my logic for the past hour or so and have got in a bit of a muddle about it all. A fresh and experienced pair of eyes would be most welcome!

How do I set up firebase analytics on my react native expo project?

I followed this documentation which seems pretty straightforward, however I keep getting error while setting analytics user id: [Error: No Firebase App '[DEFAULT]' has been created - call firebase.initializeApp()]

This is part of my App.js file:

import { auth } from './firebase.js'
import analytics from '@react-native-firebase/analytics';

const App = () => {
  
  const [currentUser, setCurrentUser] = useState(null);

  useEffect(() => {
    (async () => {
      if(currentUser){
        console.log("I have current user: ", analytics())
        try{
            await analytics().setUserId(currentUser.uid)
            console.log("all done")
        }catch(error){
          console.log("error while setting analytics user id: ", error);
        }
      }
    })();
  }, [currentUser]);

  useEffect(() => {
   const unsubscribe = auth.onAuthStateChanged((user) =>  {
        if (user) {
          setCurrentUser(user);
        }
    });
   return () => unsubscribe();
 }, []);


  if(!currentUser){
      return (
        <NavigationContainer>
          <AuthNavigator />
        </NavigationContainer>
      );
  }
  else{
    return (
        <NavigationContainer>
          <MainNavigator />
        </NavigationContainer>
    );
  }
};

export default App;

My firebase.js file:

import firebase from "firebase/compat/app";
import 'firebase/compat/firestore'
import 'firebase/compat/auth'

const firebaseConfig = {
  apiKey: "some_key",
  authDomain: "some_domain",
  databaseURL: "some_url",
  projectId: "some_project_id",
  storageBucket: "some_id",
  messagingSenderId: "id",
  appId: "id",
  measurementId: "id"
};

if (firebase.apps.length === 0) {
  firebase.initializeApp(firebaseConfig);
}


const authState = firebase.auth();
export const auth = authState;
export const firestore = firebase.firestore();

Can someone please help because I spent too much time on this issue. I followed the docs correctly, I dont understand why it is complaining for [Error: No Firebase App '[DEFAULT]' has been created - call firebase.initializeApp()]

Please dont point me to the docs, I read them multiple times, I need practical solution.

SvelteKit Chrome Extension

I am trying to use SvelteKit to make a chrome extension. From my understanding, I need a manifest.json file inside the static folder. Because chrome does not allow inline scripts, I also need a separate content.js file. However, the manifest file needs to be able to access the content.js file. To do this, I had originally put my content.js in the static folder, but then I couldn’t’ import any of my svelte components from src since static and src are on the same level. I am very lost on what to do in order to use svelte components for my chrome extension. Any advice would be greatly appreciated. Thank you.

Shadcn Select Component | How to have to select a value using a function

I have an issue when using Shadcn Select component in NextJs.

I have a selection component for choosing the location

          <Select onValueChange={createLocationQuery} defaultValue={selectedLocation || ''}>
            <SelectTrigger className='w-full h-[100x] bg-white bg-opacity-10 backdrop-blur-sm rounded-none border-opacity-20 border-2 border-white text-md'>
              <SelectValue
                placeholder={selectedLocation ? selectedLocation : 'Loading...'}
              />
            </SelectTrigger>
            <SelectContent className='max-w-[380px] bg-white bg-opacity-20 backdrop-blur-sm rounded-none text-md border-none text-white'>
              {locations.map((location: any, index: number) => (
                <SelectItem
                  key={location.id}
                  value={location.title}
                  className='cursor-pointer text-md focus:bg-slate-900 focus:text-white [&:not(:last-child)]:mb-1 rounded-none'
                >
                  {location.title}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>

The issue is that I’m updating the URL query parameters when a location is selected. If I click a button that redirects me to the same page I’m already on, the query parameters get temporarily removed.

I’ve tried using a setter function inside a useEffect where I fetch the data, treating it like a default value. This works fine whenever the component is remounted. However, when I click the same button to navigate to the current page, the query gets deleted and replaced, and the Select component retains its internal state.

For example:

If the Select component currently shows the second option as selected, and I navigate to the same page, the query and fetched data revert to the first option. However, the Select component still displays the second option.
This creates a mismatch between the displayed selection in the Select component and the actual data or query parameters.

 useEffect(() => {
    const getLocations = async () => {
      try {
        const response = (await get({
          url: 'api/menu/getLocations',
        })) as Location[];
        setLocations(response);
        if (!selectedLocation && response.length > 0) {
          createLocationQuery(response[0].title);
        }
      } catch (error) {
        console.log(error);
      }
    };
    getLocations();
  }, [router, selectedLocation]);
  const createLocationQuery = (value: string) => {
    const createQuery = createQueryString('location', value, searchParams);
    router.push(pathname + '?' + createQuery);
  };

Is there a way I could reset the select component to have the selected state as the first option using a function inside the userEffect or maybe something else?

JSON.stringify() for snapshoting instead Object.freeze()?

I am curious. I just encountered that if you are tracking object property values in time, you should use JSON.strigify() instead of Object.freeze().

It might seem as stupid question, but I would like get some educative answer, why choose one over other. I would like to avoid doing some mistakes in future.

thanks for your thoughts. 🙂

Why when using copyTo and {contentsOnly:true} it is not copying all the data that the formulas are providing from the sheet?

I am using google sheets & google scripts FYI.

I have tried using the following snippet

Sheet

When I attempt to use the following code snippet it seems to be only copying certain values from the cells and not the rest.

const exportSheetName = 'Reconcile';  // Please set the target sheet name.

  const temporaSheet = SpreadsheetApp.getActiveSpreadsheet().copy('tmp');

  const targetRange = temporaSheet.getSheetByName(exportSheetName).getDataRange();
  targetRange.copyTo(targetRange, {contentsOnly: true});

  temporaSheet.getSheets().forEach(sheet => {
    if (exportSheetName != sheet.getName()) temporaSheet.deleteSheet(sheet)
  });

  const id = temporaSheet.getId();
  const xlsxBlob = UrlFetchApp.fetch(`https://docs.google.com/spreadsheets/export?id=${id}&exportFormat=xlsx`, {headers: {authorization: `Bearer ${ScriptApp.getOAuthToken()}`}}).getBlob();

  DriveApp.createFile(xlsxBlob.setName(`${fileName}.xlsx`));

  DriveApp.getFileById(id).setTrashed(true);

This is what it looks like when I open the file created

Copied Sheet

This is the formula I am using in the cells that will not copy.

=IF(COUNTIF($A$2:$A, $A3)>1, "Duplicate", checkStatus($A3, CIL!$A$2:$A, CIL!$F$2:$F, CIL!$C$2:$C, CIL!$D$2:$D, "status"))

Flutter getting Uncaught TypeError when extending BrowserHttpClientAdapter in dio

I use a custom adapter when I instantiate Dio. But when I run my app in chrome, I see error in console and nothing is shown.

Here is the complete code:

import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:dio/browser.dart';

class CustomBrowserHttpClientAdapter extends BrowserHttpClientAdapter {
  CustomBrowserHttpClientAdapter() {
    withCredentials = true;
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final Dio dio = Dio()..httpClientAdapter = CustomBrowserHttpClientAdapter();

    return Scaffold(
      appBar: AppBar(title: Text('Dio with Custom Adapter')),
      body: Center(
        child: ElevatedButton(
          onPressed: () async {
            try {
              final response = await dio.get('https://example.com');
              print(response.data);
            } catch (e) {
              print('Error: $e');
            }
          },
          child: Text('Make Request'),
        ),
      ),
    );
  }
}

Here is the console output:

Uncaught TypeError: Class extends value undefined is not a constructor or null
    at load__packages__didgah__main_test_dart (main_test.dart.lib.js:128:13)
    at Object.execCb (require.js:1696:33)
    at Module.check (require.js:883:51)
    at Module.<anonymous> (require.js:1139:34)
    at require.js:134:23
    at require.js:1189:21
    at each (require.js:59:31)
    at Module.emit (require.js:1188:17)
    at Module.check (require.js:938:30)
    at Module.<anonymous> (require.js:1139:34)
    at require.js:134:23
    at require.js:1189:21
    at each (require.js:59:31)
    at Module.emit (require.js:1188:17)
    at Module.check (require.js:938:30)
    at Module.<anonymous> (require.js:1139:34)
    at require.js:134:23
    at require.js:1189:21
    at each (require.js:59:31)
    at Module.emit (require.js:1188:17)
    at Module.check (require.js:938:30)
    at Module.<anonymous> (require.js:1139:34)
    at require.js:134:23
    at require.js:1189:21
    at each (require.js:59:31)
    at Module.emit (require.js:1188:17)
    at Module.check (require.js:938:30)
    at Module.<anonymous> (require.js:1139:34)
    at require.js:134:23
    at require.js:1189:21
    at each (require.js:59:31)
    at Module.emit (require.js:1188:17)
    at Module.check (require.js:938:30)
    at Module.<anonymous> (require.js:1139:34)
    at require.js:134:23
    at require.js:1189:21
    at each (require.js:59:31)
    at Module.emit (require.js:1188:17)
    at Module.check (require.js:938:30)
    at Module.<anonymous> (require.js:1139:34)
    at require.js:134:23
    at require.js:1189:21
    at each (require.js:59:31)
    at Module.emit (require.js:1188:17)
    at Module.check (require.js:938:30)
    at Module.enable (require.js:1176:22)
    at Module.init (require.js:788:26)
    at callGetModule (require.js:1203:63)
    at Object.completeLoad (require.js:1590:21)
    at HTMLScriptElement.onScriptLoad (require.js:1717:29)```

Refreshing token while multiple ajax queries run in Javascript

I have an API that issues JWT access tokens and refresh tokens. The access tokens have a short life so they are refreshed often (provisionally every minute). My JS/JQ frontend is set up with $.ajaxPrefilter to check if an API call has failed with a 401 and issue a new access token while updating the refresh token’s expiry date. This works well in most situations but I am running in to an issue when a page is reloaded and three AJAX queries are made in succession. The first query calls the refresh endpoint and gets a new access token while refreshing the refresh token. However the subsequent queries fail because they send off the now stale refresh token which the refresh endpoint fails to validate. Essentially the subsequent queries try to do a token refresh before the first one has completed and fail the original AJAX queries or drop me to the login page due to failed auth.

My question would be what approach I should take to resolve this issue. I have little programming experience and can’t come up with something that works. My thinking involves somehow queuing the queries somehow or deferring them until the token has been refreshed. I could implement a solution to wait for a token refresh on page load but there are still conditions where multiple queries could realistically take place in quick succession when a token refresh is needed so that would just make the issue less likely.

Uncaught TypeError: document.getElementById(…) is null – order of elements are ok, id is known

I know this is not new and I’ve found a couple of hints how to solve it. But I cannot get rid of it. This is my simple code:

<!doctype html>
<html lang="de">
    <head>
        <title>SVG Test</title>
    </head>
    <body>
        <h1>Select a circle</h1>
        <object id="svg-object" data="circle.svg" width="200" height="200"></object>

        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400">
            <circle id="circle" class="svg-element" cx="50" cy="50" r="40" />
        </svg>

        <script>
            // do this if selected
            function handleClick(elementId) {
                alert('"' + elementId + '" selected');
            }

            // event listener
            document.getElementById("circle").addEventListener("click", function () {
                handleClick("circle");
            });

            // event listener
            document.getElementById("circle_in_svg").addEventListener("click", function () {
                handleClick("circle_in_svg");
            });
        </script>
    </body>
</html>

This shows two circles.
The svg-file “circle.svg” has exactly the same content as the three lines below <object ….>. Only the id is changed from “circle” to “circle_in_svg”.

So, this is the situation:

  • < script >… is below < object >… i.e. “circle_in_svg” should be known.
  • The two circles are shown in the correct order: first the circle in the file, second the circle inline.
  • ‘defer’ or ‘async’ doesn’t help. Btw: omitting both means for me: load the file and proceed after the file is loaded, so the id should be available.

After loading this page I get the error (F12 in mozilla): “Uncaught TypeError: document.getElementById(…) is null”. And as a matter of course it doesn’t work as intended…

Any help?