Skip to content
Advertisement

Mutationobserver not fired when innerhtml changed by javascript code

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);
Advertisement