Nyxeria
Nyxeria

Reputation: 383

Javascript creating SVG element using createElementNS sometimes returns a null

The following code has a weird quirk:

function createSVG(){
    let svgarea = document.getElementById("svgarea");
    let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    svg.setAttribute("id", "my_svg");
    svg.setAttribute("width", "100%");
    svg.setAttribute("height", "100%");
    svgarea.appendChild(svg);
}

When I run call it from script when loading page or on window.onload, the script fails

"Cannot read property 'appendChild' of null" 

at the

svgarea.appendChild(svg);

But it works normally if I call it from console. Is there a workaround for this? I suspect that the createElementNS somehow hangs before it gets to appending the result, but somehow it doesn't when calling from console.

Upvotes: 0

Views: 201

Answers (1)

It means the DOM Element #svgarea isn't there yet when you execute:
let svgarea = document.getElementById("svgarea");

When you execute the same statement from the console the DOM is there, ready

So you must delay execution of your createSVG function:

window.addEventListener("DOMContentLoaded", createSVG);

You could also use the load Event but that fires later, after all content is loaded.

If you use window.onload = you have to be 100% sure no later code will override it. addEventListener does what it says: it adds extra listeners

setTimeout(createSVG);

Also does the trick, in cases where the Events have long past, and you can't use them. No time required because setTimeout will run after the Event Loop is done, thus any DOM creation will have happened.

If you want to create SVG, you can also use HTML notation:

function createSVG(){
 document
  .getElementById("svgarea")
  .innerHTML=`<svg xmlns='http://www.w3.org/2000/svg' id='my_svg' width='100%' height='100%'></svg>`
}

Or, because innerHTML is render blocking, creates DOM nodes immediately:

function createSVG(){
 let area = document.getElementById("svgarea");
 area.innerHTML=`<svg xmlns='http://www.w3.org/2000/svg' id='my_svg'></svg>`;
 let svg = area.querySelector("svg");
 svg.setAttribute("width","100%");
 svg.setAttribute("height","100%");
}

And don't forget you probably need a viewBox attribute on those SVGs

Upvotes: 3

Related Questions