Knockout.js 3.3 — компонент перерисовки в привязке foreach

Моя модель представления состоит из наблюдаемого массива с наблюдаемыми элементами.

// viewmodel
var viewModel = function () {
    this.o = ko.observableArray();
    for (var i = 0; i < 3; i++)
    this.o.push(ko.observable(0));
};

Мне нужно изменить значения этих элементов. И для этого я создаю свой компонент. Простой пример ниже:

//custom element <component>
ko.components.register("component", {
    viewModel: function (params) {
        var self = this;
        this.value = params.value;
        console.log("init component");
        this.i = 1;
        this.change = function () {
            self.value(self.i++);
            console.log("change to " + self.value());
        }
    },
    template: "<span data-bind='text: value'></span>  <button data-bind='click:change'>Change</button>"
});

Этот компонент может изменить значение наблюдаемого элемента, которое входит в params.value.

Моя точка зрения очень проста:

<!--ko foreach:o-->
       <component params="value: $rawData"></component>
<!--/ko-->

Полный пример: http://jsfiddle.net/tselofan/xg16u5cg/7/ Проблема в том, когда значение наблюдаемого элемента в наблюдаемом массиве изменяется, компонент рендерится заново, так как он находится внутри привязки foreach. Это можно увидеть в логах. Какую лучшую практику я могу использовать в этой ситуации? Спасибо


person Tselofan    schedule 16.07.2015    source источник


Ответы (2)


Компонент воссоздается каждый раз при изменении числа, поскольку контекст компонента является числом.

http://jsfiddle.net/Crimson/xg16u5cg/8/

<!-- ko foreach: o -->
    <component params="value: $data.myNumber"></component>
<!-- /ko -->

//Test how components work in foreach binding
//custom element <component>
ko.components.register("component", {
    viewModel: function (params) {
        var self = this;
        this.value = params.value;
        console.log("init component");
        this.i = 1;
        this.change = function () {
            self.value(self.i++);
            console.log("change to " + self.value());
        }
    },
    template: "<span data-bind='text: value'></span>  <button data-bind='click:change'>Change</button>"
});


// viewmodel
var viewModel = function () {
    this.o = ko.observableArray();
    for (var i = 0; i < 3; i++)
        this.o.push({myNumber: ko.observable(0)});
};

ko.applyBindings(new viewModel());
person CrimsonChris    schedule 16.07.2015
comment
В качестве альтернативы вы все равно можете передать простое значение, но создать новое значение модели представления компонента как наблюдаемое в файле init. jsfiddle.net/xg16u5cg/9 - person Roy J; 16.07.2015
comment
Любое решение, которое позволяет избежать прямого изменения контекста компонента, будет работать. - person CrimsonChris; 16.07.2015
comment
Спасибо за ответ! CrimsonChris, ваше решение вынуждает меня изменить модель домена. Я хотел бы избежать этого. @Roy J, изменение наблюдаемого внутри компонента не приводит к изменению наблюдаемого элемента в массиве. См. jsfiddle.net/tselofan/xg16u5cg/10 . Мой код хорошо работает для наблюдаемых элементов вне привязки foreach, несмотря на изменение контекста. См. jsfiddle.net/tselofan/xg16u5cg/12 . Это связано с тем, что привязка foreach объединяет привязку шаблона, которая повторно отображает содержимое при изменении контекста. Могу ли я остановить повторную визуализацию содержимого шаблона foreach? Спасибо. - person Tselofan; 16.07.2015
comment
@Tselofan Возможно, Knockout-Repeat (github.com/mbest/knockout-repeat) будет работать для ты. - person Roy J; 16.07.2015
comment
Вы можете просто удалить состояние из компонента. Тогда вам не придется беспокоиться о том, переделает ли Knockout его. jsfiddle.net/Crimson/xg16u5cg/16 - person CrimsonChris; 16.07.2015
comment
CrimsonChris в вашем последнем компоненте решения все еще продолжает создаваться заново. Смотрите журналы. @Roy J, твое решение - ответ на мой вопрос. Оно работает, как я и ожидал. См. jsfiddle.net/tselofan/a54jnt7d/1 Пожалуйста, ответьте, чтобы я мог оценить вас. Спасибо вам всем! - person Tselofan; 17.07.2015

Knockout-Repeat (https://github.com/mbest/knockout-repeat) — это итеративный привязка, которая не создает новый контекст привязки и имеет режим foreach, поэтому она должна работать с вашим компонентом так, как вы ожидаете.

person Roy J    schedule 17.07.2015
comment
Будьте осторожны с этим перееданием. 1. Он предоставляет псевдонаблюдаемую переменную контекста $item, которая не является ko.subscribable. 2. Использует странный алгоритм перегенерации разметки при удалении элемента из наблюдаемого массива: насколько я понимаю, сначала удаляется первый узел DOM (независимо от индекса удаляемого элемента), а затем обновляется контекст остальных узлов DOM. По некоторым причинам (возможно, из-за контекста псевдоподписки) мой компонент не может обработать этот алгоритм. Спасибо за Ваш ответ. - person Tselofan; 27.07.2015