0

I'm writing an app which grabs a bunch of JSON data via AJAX, then renders the view which is constructed from the same data in an es6 template literal. Really simple version to demonstrate:

let mountPoint = document.getElementById("mountPoint");
let view = document.createElement("section");
view.id = "view";
view.innerHTML = `<section>${returnedAjaxData}</section>`;
mountPoint.innerHTML = view;
#mountPoint {
  background: #000000;
}

#view {
  background: #444444
}
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>My App</title>
</head>
<body>
  <section id="mountPoint"></section>
</body>
</html>

Where ${returnedAjaxdata} is the data returned from the Ajax call (not shown here but working fine)

The problem is that "#mountPoint" has a black background but "#view" does not have a grey background. It seems that the CSS file is run before the "#view" renders since it waits for the Ajax data before rendering.

EDIT I know how to change CSS on AJAX success for a specific element. My question is how do I run the entire stylesheet after the AJAX call returns AND the DOM is rendered. For context - the entire app will be inside "#mountPoint" so updating a single element wont help much

One possible solution would be to write the styles.min.css file after "#view" is rendered but that seems hacky... I'm wondering: how does React and other view rendering frameworks do this? They render HTML after the CSS files are read as well right? Is there a good pattern out there for this which I can learn?

HelloWorld
  • 2,480
  • 3
  • 28
  • 45
  • 1
    Possible duplicate of [jQuery: Changing the CSS on an element loaded with ajax?](https://stackoverflow.com/questions/6866043/jquery-changing-the-css-on-an-element-loaded-with-ajax) – SHOHIL SETHIA Jul 25 '17 at 05:54
  • I dont think it is. That answer references how to change a single element, I need the whole stylesheet to run after the AJAX call returns and the innerHTML is rendered – HelloWorld Jul 25 '17 at 06:07

1 Answers1

1

Element#innerHTML parses a string, and sets it as the html content of a node. The node you've created using Document#createElement is not a string. When you try to add it to mountPoint using Element#innerHTML, it's converted to string, and the string doesn't have the id view.

You need to append the node to the view using Node#appendChild or ParentNode#append (not supported by MS browsers).

In addition css selectors (id for example) are case sensitive, and mountpoint in the css is not the same as mountPoint in the html.

let mountPoint = document.getElementById("mountPoint");
let view = document.createElement("section");
view.id = "view";
view.innerHTML = `<section>returnedAjaxData</section>`;
mountPoint.appendChild(view); // append as a child of mountPoint
#mountPoint { /** renamed to mountPoint **/
  height: 40px; /** just for the example **/
  background: #000000;
}

#view {
  background: #444444
}
<section id="mountPoint"></section>

If the id in the CSS and the HTML are exactly the same Element#innerHTML will work as well:

let mountPoint = document.getElementById("mountPoint");
mountPoint.innerHTML = '<section id="view">returnedAjaxData</section>';
#mountPoint { /** renamed to mountPoint **/
  height: 40px; /** just for the example **/
  background: #000000;
}

#view {
  background: #444444
}
<section id="mountPoint"></section>
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
  • Parentnode.append() doesnt work in IE, Edge or Safari https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/append – HelloWorld Jul 25 '17 at 06:29
  • I'm going to accept this answer because it works for my example. It still doesnt work for my actual app because I need to append an HTML string to the view node and appendChild needs a DOM node not a string – HelloWorld Jul 25 '17 at 06:49
  • As long the selector (id) is similar, it works with innerHTML as well. See addition to answer. – Ori Drori Jul 25 '17 at 06:54