Knockout.js: привязки обновлений?

когда я добавляю любые новые элементы в DOM после ko.applyBindings(); был вызван, то нокаут не узнает эти новые элементы. Я могу понять, почему это происходит - они просто не индексируются нокаутом.

Итак, сначала я подумал, что это будет решено путем повторного вызова ko.applyBindings(), после добавления моих новых элементов, НО потом я понял, что для каждого вызова ko.applyBindings(), который вы делаете, соответствующие события увольняются много раз. Поэтому после применения пяти раз щелчок: привязка будет запущена пять раз, поэтому это не желаемое решение;)

Есть ли что-нибудь вроде ko.updateBindings() или что-то еще, чтобы сказать нокауту, ну... обновить привязки элементов?

привет, Крис

Ответ 1

Каждый раз, когда вы вызываете ko.applyBindings, вся DOM проверяется на привязку. В результате вы получите несколько привязок для каждого элемента, если вы делаете это более одного раза. Если вы просто хотите связать новый элемент DOM, вы можете передать этот элемент в качестве параметра функции applyBindings:

ko.applyBindings(viewModelA, document.getElementById("newElement"));

Смотрите этот вопрос:

Можете ли вы вызвать ko.applyBindings для привязки частичного просмотра?

Ответ 2

Не зная, что вы делаете, похоже, что вы ошибетесь. Ваш взгляд должен определяться вашей моделью просмотра. Таким образом, вы не должны напрямую добавлять элементы DOM, тогда вам нужно применять привязки для нокаутов.

Вместо этого вы должны обновлять свою модель представления, чтобы отразить изменение в представлении, которое затем приводит к появлению нового элемента.

Так, например, для вашего $('body').append('<a href="#" data-bind="click: something">Click me!</a>'); вместо добавления элемента DOM, когда кнопка должна быть видимой, управляйте видимостью кнопки с помощью модели представления.

Таким образом, ваша модель просмотра включает

var viewModel = { clickMeAvailable: ko.observable(false) }

И ваш HTML включает

<a href="#" data-bind="click: something, visible: clickMeAvailable">Click me!</a>

Когда состояние приложения изменяется, поэтому доступна кнопка click me, тогда вы просто viewModel.clickMeAvailable(true).

Целью этого и большой частью нокаута является отделить бизнес-логику от презентации. Таким образом, код, который делает клик меня доступным, не волнует, что щелчок меня включает в себя кнопку. Все, что он делает, - это обновление viewModel.clickMeAvailable, когда доступно клик по мне.

Например, скажем, нажмите кнопку "Я нахожу", это кнопка сохранения, которая должна быть доступна, когда форма заполнена. Вы привязываете видимость кнопки сохранения к наблюдаемой модели formValid.

Но затем вы решаете изменить ситуацию, поэтому после того, как форма будет действительна, появится юридическое соглашение, с которым необходимо согласиться до сохранения. Логика вашей формы не изменяется - она ​​все равно устанавливает formValid, когда форма действительна. Вы просто измените то, что происходит, когда formValid изменяется.

Как отмечает lassombra в комментариях к этому ответу, бывают случаи, когда прямой DOM-манипуляция может быть вашим лучшим подходом - например, сложная динамическая страница, в которой вы хотите только увлажнить части представления по мере необходимости. Но вы отказываетесь от разделения проблем, которые предоставляет Knockout, делая это. Помните, если вы планируете сделать этот компромисс.

Ответ 3

Я знаю, что вы давно спросили, но я просто наткнулся на подобную проблему. Я попытался добавить новые элементы в контейнер и дать им функцию onclick. Сначала попробовали все, что вы сделали, и даже попробовали подход ColinE . Это не было практическим решением для меня, поэтому я попытался подходить SamStephens и придумал это, что отлично подходит для меня:

HTML:

<div id="workspace" data-bind="foreach:nodeArr, click:addNode">
<div class="node" data-bind="attr:{id:nodeID},style:{left:nodeX,top:nodeY},text:nodeID, click:$parent.changeColor"></div>
</div>

JavaScript:

<script>
function ViewModel() {
var self = this;
var id = 0;
self.nodeArr = ko.observableArray();
self.addNode = function (data, event) {
    self.nodeArr.push({
        'nodeID': 'node' + id,
        'nodeX' : (event.offsetX - 25) + 'px',
        'nodeY' : (event.offsetY - 10) + 'px'
    })
    id++;
}
self.changeColor = function(data, event){
    event.stopPropagation();
    event.target.style.color = 'green';
    event.target.style.backgroundColor = 'white';
}
}
ko.applyBindings(new ViewModel());
</script>

Вы можете играть с ним в JS Fiddle, который я сделал. Надеюсь, это все еще помогает кому-то.