I have a MutationObserver that observe an element with id shipping_cost
and fire function updateTotal()
when the innerhtml of the element changed. The MutationObserver works when the innerHTML is changed from external source (such as inspect element). But when i change the innerHTML from inside javascript, MutationObserver did not get fired, where did i do wrong?
It can be seen in the code that at the end of the javascript, i tried to change innerhtml from inside javascript, but the innerhtml of element with id total
did not change, which indicates that updateTotal()
did not get fired.
However, the function updateTotal()
get fired when i change the innerhtml using inspect element (in chrome: right click -> inspect). How do i fix this ?
const subtotal = document.getElementById("subtotal"); const shipping_cost = document.getElementById("shipping_cost"); const total = document.getElementById("total"); const price_loading_text = "Loading . . ."; shipping_cost.innerHTML = price_loading_text; total.innerHTML = price_loading_text; function updateTotal() { if(shipping_cost.innerHTML != price_loading_text) { total.innerHTML = parseFloat(subtotal.innerHTML) + parseInt(shipping_cost.innerHTML); } else { total.innerHTML = price_loading_text; } } updateTotal(); observer = new MutationObserver(updateTotal); observer.observe(shipping_cost, { attributes: false, childList: false, subtree: true, characterData: true}); shipping_cost.innerHTML = "100";
<p>Subtotal: <span id="subtotal" class="subtotal">9999</span></p> <p>Shipping_cost: <span id="shipping_cost" class="shipping_cost"></span></p> <p>Total: <span id="total" class="total"></span></p>
Advertisement
Answer
Doing
shipping_cost.innerHTML = "100";
modifies the element’s children – specifically, it removes all of its existing children from the DOM and then inserts a new text node as a child. That should make it intuitive that you need not
childList: false,
but instead
childList: true,
for changes to the children to be seen.
const subtotal = document.getElementById("subtotal"); const shipping_cost = document.getElementById("shipping_cost"); const total = document.getElementById("total"); const price_loading_text = "Loading . . ."; shipping_cost.innerHTML = price_loading_text; total.innerHTML = price_loading_text; function updateTotal() { if (shipping_cost.innerHTML != price_loading_text) { total.innerHTML = parseFloat(subtotal.innerHTML) + parseInt(shipping_cost.innerHTML); } else { total.innerHTML = price_loading_text; } } updateTotal(); observer = new MutationObserver(updateTotal); observer.observe(shipping_cost, { attributes: false, childList: true, subtree: true, characterData: true }); shipping_cost.innerHTML = "100";
<p>Subtotal: <span id="subtotal" class="subtotal">9999</span></p> <p>Shipping_cost: <span id="shipping_cost" class="shipping_cost"></span></p> <p>Total: <span id="total" class="total"></span></p>
That said, I’d recommend only using an observer when code you have no control over makes a mutation to the DOM. If you have control over all the code in the app, it’s usually far easier to just call the desired function after changing the DOM. For example, don’t do
shipping_cost.innerHTML = "100";
but do
const updateShippingCost = (newCost) => { shipping_cost.innerHTML = newCost; total.innerHTML = Number(subtotal.innerHTML) + newCost; }; updateShippingCost(100);