4

What I'm looking to do is detach some nodes using jQuery's detach method, update my ViewModel, attach my nodes back, and have the values be updated.

Is this possible?

Here's a full fiddle of what I'm shooting for. Basically, I'd like to be able to go from left to right, click detach, update, and attach and have fresh values in the textboxes.


UPDATE

Based on RP's answer, the best bet, assuming this fits your use case, is to attach them to the dom hidden, update your viewmodel, and then show your nodes. Something like this works for me:

$("#updateAndAttach").click(function () {
    var junk = $("<div />").css("display", "none");
    junk.append(nodes);
    $("#home").append(junk);

    vm.a("AAA");
    vm.b("BBB");

    $(nodes).unwrap();
});

END UPDATE


Here's the full code:

JavaScript

$(function () {

    function ViewModel() {
        this.a = ko.observable("a");
        this.b = ko.observable("b");
    }

    var vm = new ViewModel();

    ko.applyBindings(vm, document.getElementById("home"));

    var nodes = null;

    $("#detach").click(function () {
        nodes = $("#home").children().detach();
    });

    $("#attach").click(function () {
        $("#home").append(nodes);
    });

    $("#update").click(function () {
        vm.a("AAA");
        vm.b("BBB");
    });
})();

HTML:

<div id="home">
    <input type="text" data-bind="value: a" />
    <input type="text" data-bind="value: b" />
</div>

<button id="detach">Detach</button>
<button id="update">Update</button>
<button id="attach">Attach</button>
Adam Rackis
  • 82,527
  • 56
  • 270
  • 393

3 Answers3

3

The evaluation of the bindings in a single data-bind are wrapped in a computed observable that will dispose of itself when it is re-evaluated and recognizes that it is not part of the current document.

So, there is not a simple workaround that would allow you to do what you are trying. You could certainly hide the elements while updates are being made and then unhide them.

RP Niemeyer
  • 114,592
  • 18
  • 291
  • 211
  • 1
    Thanks. For me, the workaround is simple—I only need to update right before I re-attach, so my edit above does that quite simply and nicely. – Adam Rackis May 03 '12 at 19:10
1

What happens here is when you call detach method, ko loses bindings to detached nodes. The easiest way to make it work is to re-apply bindings each time you detach and attach nodes.

See this jsfiddle: http://jsfiddle.net/EZFDt/

Edit: With that workaround in place, keep in mind there may be performance implications. Perhaps you can re-think the way you approach the problem - can you move nodes to a different, hidden location instead of detaching them? Can you simply hide them?

MK_Dev
  • 3,291
  • 5
  • 27
  • 45
  • Thanks for the answer, but I think there are problems with re-applying bindings multiple times. http://stackoverflow.com/a/8284095/352552 – Adam Rackis May 03 '12 at 18:38
  • Right. However, applyBindings method accepts a node parameter, which applies bindings just to that node. – MK_Dev May 03 '12 at 18:40
  • True! If you're inserting new dom nodes, that can come in handy. I was just looking to update my VM while the nodes are detached. +1 – Adam Rackis May 03 '12 at 18:47
  • 2
    You would need to be very cautious about reapplying bindings to existing elements. In this case, the only reason that the bindings are disposed is because the observables that they depend on are updated. Depending on the use case, this may or may not be true. Always best to avoid applying bindings multiple times to avoid extra handlers. Here is a sample that shows that event handlers would still be lingering in this scenario: http://jsfiddle.net/rniemeyer/LS72r/1/. After detaching, updating, reattaching, and reapplying the button click will be handled twice. – RP Niemeyer May 03 '12 at 20:20
1

It's a while since you asked the question, but I have found using detach, then immediately append to some valid location in the DOM keeps all bindings working nicely. You may then detach, append to wherever you need it as your application changes state.

I use it for sections with multiple events attached, like JQUI elements, forms and the like so that I can keep one copy running around, and just append to the page I go to. eg. a Signup form, which also functions as Edit Profile.

In your case, initially appending it into a 'visibility:hidden;' node at some point that was clearly for detached elements could be reasonable.

Don Have a great day