Можно ли выйти из привязки ко foreach до завершения рендеринга?
Это мой первый пост на SO, поэтому, пожалуйста, будьте осторожны со мной:)
Я создаю веб-приложение с Durandal.js, и у меня возникает ситуация, когда я запускаю простое связывание данных foreach нокаута, которое перебирает ko.observableArray и создает дочерние представления для каждого элемента в массиве. Этот массив состоит из нескольких дочерних view / viewmodels, которые я хочу визуализировать на странице, но массив может содержать большое количество элементов за раз (иногда более 400). Приложение также может иметь несколько страниц результатов, и я обрабатываю подкачку страниц, заменяя содержимое ko.observableArray при нажатии на новую страницу.
Проблема, с которой я иногда сталкиваюсь (это не каждый раз, но это повторяется), заключается в том, что я получаю ошибку, вызванную knockout.js (я использую knockout v3.0.0), который говорит следующее: "Uncaught TypeError: Невозможно прочитать свойство 'insertBefore' из null".
Вот часть метода prepend для виртуальных элементов knockout.js, которая выдает ошибку:
prepend: function(containerNode, nodeToPrepend) {
if (!isStartComment(containerNode)) {
if (containerNode.firstChild)
containerNode.insertBefore(nodeToPrepend, containerNode.firstChild);
else
containerNode.appendChild(nodeToPrepend);
} else {
// Start comments must always have a parent and at least one following sibling (the end comment)
containerNode.parentNode.insertBefore(nodeToPrepend, containerNode.nextSibling);
}
}
Покопавшись в нокаут-коде, я вижу, что то, что называется null, является containerNode.parentNode. В моем фрагменте HTML-кода ниже, containerNode.parentNode - это #photosContainer, поэтому я нахожу странным, что это null, поскольку foreach, очевидно, все еще работает (так как я получаю сообщение об ошибке для каждого элемента, который еще не отображался).
Вот некоторые фрагменты кода из моего приложения Durandal: HTML-код из моего представления, который содержит привязку foreach, которая перебирает observableArray 'photos' и составляет дочернее представление:
<div id='photosContainer' data-bind="visible: !video_mode_on(), foreach: photos">
<!-- ko compose: $data --><!--/ko-->
</div>
и вот код из моей viewmodel, который в основном заменяет содержимое observableArray 'photos':
newHome.prototype.getPhotos = function() {
var self = this;
var defs = [];
var arr = [];
var args, newArr;
self.rawPhotos().forEach( function( set ) {
defs.push( self.some_more_all( set.mf, set.images ) );
});
$.when.apply($, defs).done(function( res ) {
args = Array.prototype.slice.call(arguments, 0);
newArr = args.sort();
newArr.forEach( function( set ) {
set.arr.forEach( function( p ) {
arr.push( self.addPhoto( p, self.mfOwnedByViewer( set.mf ) ? { ownedByViewer: true } : { ownedByViewer: false, owner_uuid: set.mf.owner_uuid } ) );
});
});
self.photos( arr );
});
};
Кажется, ошибка, о которой я упоминал, возникает, когда я перехожу на другую страницу результатов до того, как привязка foreach завершилась в моем представлении. Итак, мой вопрос: есть ли способ остановить или прервать привязку foreach в моем представлении, чтобы я мог перейти на другую страницу результатов, не дожидаясь отображения текущего списка результатов?
Также некоторые вещи, которые я пробовал, но не помогли: я сначала удалял все содержимое массива photos, а затем вставлял в него непосредственно при запуске моей функции getPhotos(), но думал, что ошибка могла быть вызвана пустой массив. Я также попытался запустить функцию knoout ko.virtualElements.emptyNode() в #photosContainer перед тем, как выполнить итерацию по массиву rawPhotos() в моей функции getPhotos(), чтобы посмотреть, не приведет ли это к очистке незаконченных визуализаций в привязке foreach представления, но похоже, это тоже ничего не делает. Я попытался обернуть мою компоновочную привязку функцией проверки, чтобы увидеть, существует ли узел #photosContainer следующим образом:
<div id='photosContainer' data-bind="visible: !video_mode_on(), foreach: photos">
<!-- ko if: $parent.checkForPhotosContainer() -->
<!-- ko compose: $data --><!--/ko-->
<!-- /ko -->
</div>
и функция проверки:
newHome.prototype.checkForPhotosContainer = function() {
var self = this;
var el = $(self.element).find('#photosContainer');
if( el.length ) {
return true;
} else {
return false;
}
};
Пока что ничего не сработало, и у меня заканчиваются идеи (и волосы!!). Любая помощь будет принята с благодарностью!
1 ответ
Кажется, что нет способа остановиться или вырваться из ко foreach
связывание, как указано в ссылке Магнуса Алина на Как замкнуть Array.forEach, например, вызвать прерывание? Однако основная причина моей проблемы была связана с тем, что я использовал виртуальные элементы, а не обычные элементы.
Для тех, кто сталкивается с проблемой нокаута, жалуется на "Uncaught TypeError: Невозможно прочитать свойство 'insertBefore' of null" и использует виртуальные элементы для создания дочерних представлений в ko.observableArray с использованием foreach
связывание, попробуйте заменить ваши виртуальные элементы нормальными элементами.
Поэтому замените HTML-код на ваш взгляд следующим образом:
<div data-bind="foreach: myObservableArray">
<!-- ko compose: $data --><!--/ko-->
</div>
с чем-то вроде этого:
<div data-bind="foreach: myObservableArray">
<div data-bind="compose: $data"></div>
</div>