How to update an HTML string with an element from DOM

Viewed 179

I'm trying to update a stringify HTML element with element from the DOM. This stringify HTML element is in an array in the localStorage.

First, here is how I convert it into manipulable HTML :

let toBeUpdated = document.createElement('div');
toBeUpdated.innerHTML = `${var_stringify_html_from_localstorage}`;
toBeUpdated = toBeUpdated.firstElementChild;

This toBeUpdated element is a div that contains, among other thing, an element with id updateMe. I want to update this "virtual" (not visible) #updateMe element with the one from the DOM.

I tried first :

let updateme = toBeUpdated.querySelector("#updateMe");
let updateme_DOM = document.querySelector("#updateMe");

toBeUpdated.replaceChild(updateme, updateme_DOM);

Which returns Uncaught DOMException: Node.replaceChild: Child to be replaced is not a child of this node

And secondly I tried :

let updateme = toBeUpdated.querySelector("#updateMe");
let updateme_DOM = document.querySelector("#updateMe");

updateme.replaceWith(updateme_DOM);

Which removes the originale #updateMe from the DOM and dosn't update the toBeUpdated element.

I'm obviously missing something, but I can't see what...

I tried to reproduce as much as possible my situation :

//initial state of local storage
let motd = ["<div id='toBeUpdated'><h1>Hello World</h1><p id='updateMe'>Message of tomorrow</p></div>"];
window.localStorage.setItem('motds', JSON.stringify(motd));

// My situation, later in the code
let motds = JSON.parse(window.localStorage.getItem('motds'));
let toBeUpdated = document.createElement('div');
toBeUpdated.innerHTML = `${motds[0]}`;
toBeUpdated = toBeUpdated.firstElementChild; // this is the div#toBeUpdated

let DOMUpdateMe = document.getElementById('updateMe');
let storageUpdateMe = toBeUpdated.querySelector("#updateMe"); // getElementById doesn't work here

// Replace
storageUpdateMe.replaceWith(DOMUpdateMe);

// Back in local storage
motds[0] = toBeUpdated.outerHTML;
window.localStorage.setItem('motds', JSON.stringify(motds));
<body>
  <div id="toBeUpdated">
    <h1>Hello World</h1>
    <p id="updateMe">Message of tomorrow</p>
  </div>
</body>

3 Answers

It works using firstChild rather than firstElementChild

let toBeUpdated = document.createElement('div');
//toBeUpdated.innerHTML = `${var_stringify_html_from_localstorage}`;
toBeUpdated.innerHTML = `<div id="updateMe">New DIV</div>`;
let updateme = document.getElementById('updateMe')
updateme.replaceWith(toBeUpdated.firstChild);
<div id='updateMe'>Old DIV</div>

It seems the only thing you're missing is cloning the DOM node before inserting it into the non-DOM.

Here's a step-by-step reproduction of your code changing only this, that works. I also set the initial state of localStorage to "Message of today" for clarity.

localStorage is emulated with variables, as it triggers a security error inside snippet due to CORS

//initial state of local storage
let motd = ["<div id='toBeUpdated'><h1>Hello World</h1><p id='updateMe'>Message of today</p></div>"];
//window.localStorage.setItem('motds', JSON.stringify(motd));

//Read from local storage
//let motds = JSON.parse(window.localStorage.getItem('motds'));
const motds = JSON.parse(JSON.stringify(motd)); //Simulate local storage
console.log("In storage:", motds);

//Create element outside of DOM
const toBeUpdated = document.createElement('div');
toBeUpdated.innerHTML = motds[0];
console.log("To be updated:", toBeUpdated.outerHTML);

//Get part to update
const DOMUpdateMe = document.getElementById('updateMe');
const storageUpdateMe = toBeUpdated.querySelector("#updateMe");
console.log(DOMUpdateMe, storageUpdateMe);
//Replace part outside of DOM with clone of part from DOM
storageUpdateMe.replaceWith(DOMUpdateMe.cloneNode(true));
console.log(toBeUpdated.outerHTML);

//Store back
motds[0] = toBeUpdated.outerHTML;
motd = JSON.stringify(motds); //Simulate local storage
console.log(motd);
//window.localStorage.setItem('motds', JSON.stringify(motds));
<body>
  <div id="toBeUpdated">
    <h1>Hello World</h1>
    <p id="updateMe">Message of tomorrow</p>
  </div>
</body>

Shouldn't you be using a simple newUpdateMe = DOMUpdateMe;

//initial state of local storage
let motd = ["<p class='updateMe'>Message of the day<p>"];
window.localStorage.setItem('motds', JSON.stringify(motd));

// My situation, later in the code
let motds = JSON.parse(window.localStorage.getItem('motds'));
let dOMUpdateMe = document.querySelectorAll('#toBeUpdated > *');

let counter = 0;
dOMUpdateMe.forEach(function(dOMToUpdate) {
  console.log(dOMToUpdate);
  if(dOMToUpdate.classList.contains('updateMe')) {
    motds[counter] = dOMToUpdate.outerHTML;
    counter++;
  }
})
window.localStorage.setItem('motds', JSON.stringify(motds));
<div id="toBeUpdated">
  <h1 class="updateMe">Hello World</h1>
  <p class="updateMe">Update Me</p>
  <p class="no">No not Update Me</p>
  <p class="no">No not Update Me</p>
  <p class="no">No not Update Me</p>
  <p class="updateMe">Update Me too</p>
  <p class="no">No not Update Me</p>
</div>

Related