Как очистить / удалить наблюдаемые привязки в нокауте.Джей?
Я создаю функциональность на веб-странице, которую пользователь может выполнять несколько раз. Через действие пользователя объект / модель создается и применяется к HTML с помощью ko.applyBindings().
HTML с привязкой к данным создается с помощью шаблонов jQuery.
пока все хорошо.
когда я повторяю этот шаг, создавая второй объект / модель и вызывая ko.applyBindings() я сталкиваюсь с двумя проблемами:
- разметка показывает предыдущий объект / модель, а также новый объект/модель.
- возникает ошибка javascript, связанная с одним из свойств объекта/модели, хотя он все еще отображается в разметке.
чтобы обойти эту проблему ,после первого прохода я называю jQuery.пустой () для удаления шаблонного HTML, который содержит все атрибуты привязки данных, так что он больше не находится в DOM. Когда пользователь запускает процесс для второго прохода HTML с привязкой к данным повторно добавляется в файл ДОМ.
но, как я уже сказал, когда HTML повторно добавляется в DOM и повторно привязывается к новому объекту/модели, он по-прежнему включает данные из первого объекта/модели, и я все еще получаю ошибку JS, которая не возникает во время первого прохода.
вывод, по-видимому, заключается в том, что Knockout удерживает эти связанные свойства, даже если разметка удалена из DOM.
Итак, что я ищу, это средство удаления этих связанных свойств из нокаута; сказав нокаутом, что больше нет наблюдаемой модели. Есть ли способ сделать это?
EDIT
основной процесс заключается в том, что пользователь загружает файл; затем сервер отвечает объектом JSON, привязанный к данным HTML добавляется в DOM, затем объектная модель JSON привязывается к этому HTML с помощью
mn.AccountCreationModel = new AccountViewModel(jsonData.Account);
ko.applyBindings(mn.AccountCreationModel);
после того, как пользователь сделал некоторые выборы на модели, тот же объект отправляется обратно на сервер, HTML с привязкой к данным удаляется с этого момента DOM, а затем у меня есть следующий JS
mn.AccountCreationModel = null;
когда пользователь хочет сделать это еще раз, все эти действия повторяются.
Я боюсь, что код слишком "вовлечен", чтобы сделать демо jsFiddle.
9 ответов:
вы пробовали вызвать метод чистого узла knockout на вашем элементе DOM, чтобы избавиться от связанных с памятью объектов?
var element = $('#elementId')[0]; ko.cleanNode(element);
затем применение нокаутирующих Привязок снова только к этому элементу с вашими новыми моделями представления обновит вашу привязку представления.
для проекта, над которым я работаю, я написал простой
ko.unapplyBindings
функция, которая принимает узел jQuery и логическое значение remove. Сначала он разблокирует все события jQuery какko.cleanNode
метод не заботится об этом. Я проверил на утечку памяти, и это, кажется, работает просто отлично.ko.unapplyBindings = function ($node, remove) { // unbind events $node.find("*").each(function () { $(this).unbind(); }); // Remove KO subscriptions and references if (remove) { ko.removeNode($node[0]); } else { ko.cleanNode($node[0]); } };
вы можете попробовать использовать с привязкой, что нокаут предлагает: http://knockoutjs.com/documentation/with-binding.html Идея состоит в том, чтобы использовать привязки один раз, и всякий раз, когда ваши данные изменяются, просто обновите свою модель.
Допустим, у вас есть модель представления верхнего уровня storeViewModel, ваша корзина представлена cartViewModel, и список товаров в этой корзине-скажем cartItemsViewModel.
вы бы привязали модель верхнего уровня-storeViewModel ко всему страница. Затем вы можете отделить части своей страницы, которые отвечают за корзину или элементы корзины.
предположим, что cartItemsViewModel имеет следующую структуру:
var actualCartItemsModel = { CartItems: [ { ItemName: "FirstItem", Price: 12 }, { ItemName: "SecondItem", Price: 10 } ] }
cartItemsViewModel может быть пустым в начале.
шаги будут выглядеть так:
определение Привязок в html. Отделите привязку cartItemsViewModel.
<div data-bind="with: cartItemsViewModel"> <div data-bind="foreach: CartItems"> <span data-bind="text: ItemName"></span> <span data-bind="text: Price"></span> </div> </div>
модель магазина приходит от ваш сервер (или создается любым другим способом).
var storeViewModel = ko.mapping.fromJS(modelFromServer)
определите пустые модели на модели вида верхнего уровня. Тогда структура этой модели может быть обновлена с фактические данные.
storeViewModel.cartItemsViewModel = ko.observable(); storeViewModel.cartViewModel = ko.observable();
привязать модель представления верхнего уровня.
ko.applyBindings(storeViewModel);
когда объект cartItemsViewModel доступен, назначьте его ранее определенному заполнитель.
storeViewModel.cartItemsViewModel(actualCartItemsModel);
если вы хотите очистить корзину товаров :
storeViewModel.cartItemsViewModel(null);
Knockout позаботится о html-т. е. он появится, когда модель не пуста, и содержимое div (тот, у которого есть "с привязкой") исчезнет.
Я должен позвонить ко.applyBinding каждый раз, когда кнопка поиска нажимает, и отфильтрованные данные возвращаются с сервера, и в этом случае следующая работа для меня без использования ko.cleanNode.
Я испытал, если мы заменим foreach шаблоном, то он должен работать нормально в случае коллекций / observableArray.
вы можете найти этот сценарий полезен.
<ul data-bind="template: { name: 'template', foreach: Events }"></ul> <script id="template" type="text/html"> <li><span data-bind="text: Name"></span></li> </script>
вместо того, чтобы использовать внутренние функции KO и заниматься удалением обработчика событий jQuery, гораздо лучше использовать
with
илиtemplate
привязки. Когда вы это делаете, ko воссоздает эту часть DOM, и поэтому она автоматически очищается. Это также рекомендуется способ, см. здесь:https://stackoverflow.com/a/15069509/207661.
я думаю, что было бы лучше сохранить привязку все время, и просто обновить данные, связанные с ним. Я столкнулся с этой проблемой, и обнаружил, что просто вызов с помощью
.resetAll()
метод на массиве, в котором я хранил свои данные, был самым эффективным способом сделать это.в основном вы можете начать с некоторого глобального var, который содержит данные, которые будут отображаться через ViewModel:
var myLiveData = ko.observableArray();
мне потребовалось некоторое время, чтобы понять, что я не мог просто сделать
myLiveData
нормальный массив -- этоko.oberservableArray
часть была важна.затем вы можете идти вперед и делать все, что вы хотите
myLiveData
. Например, сделать$.getJSON
звоните:$.getJSON("http://foo.bar/data.json?callback=?", function(data) { myLiveData.removeAll(); /* parse the JSON data however you want, get it into myLiveData, as below */ myLiveData.push(data[0].foo); myLiveData.push(data[4].bar); });
после того, как вы сделали это, вы можете пойти дальше и применить привязки с помощью ViewModel, как обычно:
function MyViewModel() { var self = this; self.myData = myLiveData; }; ko.applyBindings(new MyViewModel());
тогда в HTML просто используйте
myData
как обычно.таким образом, вы можете просто гадить с myLiveData из любой функции. Например, если вы хотите обновлять каждые несколько секунд, просто оберните это
$.getJSON
строка в функции и вызовsetInterval
на нем. Вам никогда не нужно будет удалять привязку, пока вы помните, чтобы сохранитьmyLiveData.removeAll();
в строке.если ваши данные действительно огромны, пользователь даже не сможет заметить время между сбросом массива, а затем добавлением самых последних данных обратно.
недавно у меня была проблема с утечкой памяти и
ko.cleanNode(element);
не сделал бы этого для меня -ko.removeNode(element);
сделал. Javascript + Нокаут.утечка памяти js - как убедиться, что объект уничтожается?
вы думали об этом:
try { ko.applyBindings(PersonListViewModel); } catch (err) { console.log(err.message); }
Я придумал это, потому что в нокаут, я нашел этот код
var alreadyBound = ko.utils.domData.get(node, boundElementDomDataKey); if (!sourceBindings) { if (alreadyBound) { throw Error("You cannot apply bindings multiple times to the same element."); } ko.utils.domData.set(node, boundElementDomDataKey, true); }
Так что для меня это не совсем проблема, которая уже связана, ее ошибка не была поймана и решена...
я обнаружил, что если модель представления содержит много Привязок div, лучший способ очистить
ko.applyBindings(new someModelView);
использование:ko.cleanNode($("body")[0]);
Это позволяет вызвать новыйko.applyBindings(new someModelView2);
динамически без беспокойства о том, что предыдущая модель представления все еще привязана.