5

I would like to reset the DOM to original state and then manipulate it again.

I have found that the best way to do this is as follows:

// Clone the Dom and assign it to a variable
divClone = $("#document").clone();

// .... More Code ......

// When required, replace the DOM with with the cloned variable. 
       $("#document").replaceWith(divClone);   

The only problem is that you cannot manipulate the newly reseted DOM again.

I have put together a JSFiddle which uses a simple example of adding a class. You can click on the "test" link to add a a class. You can then click on "Reset" to return the DOM back to its original state. However, if you click on the "test" link again, no more classes will be added to the restored DOM. (Obviously, this is just a simplified example. There are better ways of removing and adding classes).

How can I manipulate the restored DOM?

Community
  • 1
  • 1
big_smile
  • 1,487
  • 4
  • 26
  • 59
  • Does it work if you add classes to divClone? – thedayofcondor Nov 11 '12 at 16:35
  • @thedayofcondor The classes is just a simplified example. My actual page has several scripts, so I don't want to have to include the scripts twice (ie I don't want to have one set of scripts for the original DOM and then a second set of scripts which have been re-written so they work on the cloned dom). – big_smile Nov 11 '12 at 16:44
  • what I mean is, if it works on the copy it means that $("#document") refers to the old version. You could try restructuring your scripts and having 2 copies, "original" and "new", d $("#document").replaceWith(new);, work on the "new" instead of using $("#document") and to reset it just awap the variables – thedayofcondor Nov 11 '12 at 16:51

1 Answers1

6

Your code works as expected, the problem is the DOM you cloned does not have handlers bound to it.

You have 2 options, first one is to clone after all the handlers are bound, passing true to the withDataAndEvents clone method argument:

$(".test").click(function() {
    $("#document").addClass("green");
});

$(".reset").click(function() {
    $("#document").replaceWith(divClone.clone(true));
});

var divClone = $("#document").clone(true);

Fiddle


The 2nd option is to use event delegation.

var divClone = $("#document").clone();

$(document).on('click', '.test', function() {
    $("#document").addClass("green");
}).on('click', '.reset', function() {
    $("#document").replaceWith(divClone.clone());
});

Fiddle

The drawback to this second approach is that all events have to bubble up to the document level and you can't cancel the bubbling with event.stopPropagation() then.


Edit: Updated answer to replace with a clone of the clone, so that the original clone always stays safe at initial state and can serve as base for later resets.

Fabrício Matté
  • 69,329
  • 26
  • 129
  • 166
  • 1
    That works perfectly! Out of curiosity, why is the initial `divClone = $("#document").clone(true)` placed at the end of the document? Shouldn't it go at the top, so it can get the original pre-manipulated DOM? (I note that moving it to the top stops it from working, which seems counter-intuitive!!) – big_smile Nov 11 '12 at 17:32
  • 2
    @big_smile The `true` argument tells jQuery to clone the element with its event handlers. If you move it to the beginning of the code, the cloned element(s) won't have any click handlers as you haven't attached them yet. `=]` – Fabrício Matté Nov 11 '12 at 17:35