6

By default, KO "will only render the template for the new item and will insert it into the existing DOM".

Is there a way to disable this feature (as in, force KO to render all items anew)?

Ilya Ayzenshtok
  • 721
  • 2
  • 7
  • 18

2 Answers2

7

I came across a similar problem today and was able to solve it for my team's issue by replacing the template with a custom binding that first clears all ko data and empties the container before rendering.

http://jsfiddle.net/igmcdowell/b7XQL/6/

I used a containerless template like so:

  <ul data-bind="alwaysRerenderForEach: { name: 'itemTmpl', foreach: items }"></ul>

and the custom binding alwaysRerenderForEach:

ko.bindingHandlers.alwaysRerenderForEach = {
  init: function(element, valueAccessor) {
    return ko.bindingHandlers.template.init(element, valueAccessor);
  },
  update: function(element, valueAccessor, allBindings, viewModel, context) {
    valueAccessor().foreach(); // touch the observable to register dependency
    ko.utils.domData.clear(element); // This will cause knockout to "forget" that it knew anything about the items involved in the binding.
    ko.utils.emptyDomNode(element); //Because knockout has no memory of this element, it won't know to clear out the old stuff.
    return ko.renderTemplateForEach(valueAccessor().name, valueAccessor().foreach, {}, element, context);
  }
};

Obviously a little late as an answer to your query, but may help others who hit this off a search (as I did).

igmcdowell
  • 151
  • 1
  • 5
7

If you use jQuery.tmpl's native {{each koObservableArray()}} syntax Knockout cant update single items but must rerender the entire template

see more here: http://knockoutjs.com/documentation/template-binding.html

the template engine’s native ‘each’ support: after any change, the template engine is forced to re-render everything because it isn’t aware of KO’s dependency tracking mechanism.

You only get the "default" behavior if you use the foreach template mode, i.e.:

<div data-bind='template: { name: "personTemplate", 
                            foreach: someObservableArrayOfPeople }'> </div>
Rickard
  • 2,325
  • 13
  • 22
  • I've looked at {{each}}, but the problem with this approach is that the template I'm using is common for three different collection inside my KO model. Therefore, I either need to parametrize template invocation, or create a separate template for each collection. – Ilya Ayzenshtok Sep 22 '11 at 15:02
  • why whould foreach solve your problem while {{each}} doesn't. maybe you can provide some code? – Rickard Sep 22 '11 at 15:07
  • 3
    If you want to use `{{each}}` with a reusable template, then you can pass your array in using the `data` parameter rather than `foreach` and then `{{each $data}}` – RP Niemeyer Sep 22 '11 at 17:01
  • @Rickard: I've an object that contains properties GalleryA, GalleryB, and GalleryC. Each gallery contains a number of ImageItems. KO's foreach allows to me render separate containers for each gallery. However, if I modify the gallery (e.g., upload a new image to it) on the client side, I need to re-render the entire containing div due to the gallery plugin that i'm using (Galleriffic). – Ilya Ayzenshtok Sep 25 '11 at 05:27
  • @RPNiemeyer: could you please provide an example? – Ilya Ayzenshtok Sep 25 '11 at 05:28