---
title: Continuing javascript execution after total DOM body replacement using DOM mutation observers
layout: post
---
As part of the translation platform we're building, I needed to implement the following workflow:

* If the DOM has been modified previously, then restore the DOM and run the substitution function.
* If the DOM hasn't been modified, then just run the substitution function.

The problem was that whenever I ran $("body").html(this.original_document); in the first of these cases, the javascript would stop executing. I think this is because the object that triggered the event was destroyed, even though the script was in the head tag.

In other words, whenever I replace the body tag of the HTML, my javascript immediately stops and I can't call the next function. I also tried using setTimeout to somehow defer this into a space that wouldn't be picked up by garbage collection or anything else.

I eventually worked out that I can solve this problem by using DOM Mutation Observers. The first thing I do, now, when the page loads is setup a DOM Mutation Observer thus (I'm using a mixture of coffeescript and javascript here):

    this.continue_action = ""
    `
    var target = document.body;
    var observer = new MutationObserver(this.handle_state_continuity);
    var config = { attributes: true, childList: true, characterData: true };

    observer.observe(target, config);
    `

This basically says call the handle_state_continuity function whenever the contents of the body changes at any depth, in any way. Inside the event-firing method, I then have:

      startSubstitution: (event = {}) =>
        if this.original_document == ""
          this.original_document = `$("body").html()`

        if this.original_document != `$("body").html()`
          this.continue_action = "substitute"
          console.log("Annotran: Restoring DOM to original state.")
          `
          $("body").html(this.original_document);
          `
          return null
        else
          console.log("Annotran: Starting substitution directly.")
          this.makeSubstitution(event)

The important part to note here is that, in the case where it changes the body html, it first preserves the next action: this.continue_action = "substitute".

The final part needed to glue this all together is the handle_state_continuity function, which for me looks like this:

      handle_state_continuity: (mutation = null) =>
        if this.continue_action != ""
          this.continue_action = ""
          console.log("Annotran: Starting substitution via state machine.")
          this.makeSubstitution(null)


And, tada! Now, when startSubstitution is called twice, the console output is:

Annotran: Starting substitution directly. [first time]
Annotran: Restoring DOM to original state. [second time]
Annotran: Starting substitution via state machine.