I'm loading pages via ajax, on the start of each ajax request I clean the page and then load applybindings on the new page that is added. I keep a persistent model throughout, it's the view that updates.
addEventListeners(){
this.subscriptions.push(PubSub.subscribe('route.start', this.removeShopView));
this.subscriptions.push(PubSub.subscribe('route.success', this.addShopView));
}
removeShopView(){
ko.cleanNode(this.currentPage);
}
addShopView(){
this.currentPage = document.querySelector('.page-context');
ko.applyBindings(this.model, this.currentPage);
}
My problem is that in cleaning the node, I seem to be erasing the event listener attached to my anchor link on the page. This anchor link contains an element displays a counter of products in my model
<ul>
<li><a class='nav-bag' href="/bag">Bag<span data-bind='text: counter'></span></a></li>
</ul>
This event I have setup elsewhere no longer gets triggered, my page refreshes instead of running the ajax call.
setupLinks(){
this.pageContextWrap.addEventListener("click", (e) => {
this.linkClickType = undefined;
if (e.target && e.target.nodeName.toLowerCase() == 'a') {
if(href.indexOf(document.domain) === -1) {
console.log("outside link");
this.href = false;
return;
}
// anchor link is local page, ajax load the href
this.doAjaxCall();
e.preventDefault();
e.stopPropagation();
}
});
}
Is there a better way to go about this? Does cleaning the node remove all associated event listeners?
First, as you found, you should not use
cleanNode
.Second, you should prefer to have Knockout manage the entire DOM rather than a chunk of it. In your case, you're handling the app the old-fashioned manipulate-the-DOM-yourself way, and managing the changing content with Knockout.
All you really need is a version of the html binding that applies bindings to its content. A simple custom binding handler using
applyBindingsToDescendants
can make that work. Example: