luisbg
luisbg

Reputation: 574

KNOCKOUT JS observableArray duplicate

My html page is :

<div data-role="content">   
    <div id="menu">
        <ul id="menu" data-role="listview" class="ui-listview " 
            data-bind="foreach: menu">
            <li>
                <a data-bind="text:name, attr: {href: urlmenu}"></a>
                <a href="#"  data-bind="{ click: $parent.remove }" 
                   data-role="button" data-icon="delete"></a>
            </li>
        </ul>
     </div> 
</div>

<div data-role="footer" data-position="fixed">
    <div data-role="navbar">
        <ul id="footer">
            <li><a href="#home" data-icon="home">Home</a></li>
            <li><a href="#Asignaturas" data-icon="grid">Asignaturas</a></li>
            <li><a href="#bandejaentrada" data-icon="mail">Mensajes</a></li>
        </ul>
    </div>
</div>

And my JS code is :

$( document ).on( "pagebeforechange" , function(e, data) {
      var toPage = data.toPage[0].id;

     if( toPage == "home"){
         ko.cleanNode(document.getElementById('menu'));
         menu();
     }
});

function menuViewModel(){
    var self = this;
    self.menu = ko.observableArray([]);
    self.menu.removeAll();
    self.menu = ko.observableArray([
                    new EditMenuViewModel("Perfil"),
                    new EditMenuViewModel("Asignaturas")
                ]);
}

function EditMenuViewModel(name) {
    this.name = ko.observable(name);
    this.urlmenu = ko.observable("#"+name);        
};    

function menu(){
    var menuviewModel = new menuViewModel();
    ko.applyBindings(menuviewModel, document.getElementById('menu'));       
}

When I load my page for the first time everything works fine, but when I click on link footer home, the array content is duplicated.

Example is here:

First Load

after click footer home link

Any idea?

Thanks

Upvotes: 1

Views: 1811

Answers (2)

user1827502
user1827502

Reputation: 9

This is old thread, but I've found a (ugly) way to overcome it: before the cleaning, I'm caching the observable array values and set it with only 1 value. After the rebind, I'm restoring the cached values. Something like this:

var self = this;
self.myArray = ko.observableArray(['val1', 'val2']);
var tempArray = [];
self.BeforeCleaning = function () {
    tempArray = self.myArray()
    self.myArray(['temp value']);
};

self.AfterRebinding = function () {
    self.myArray(tempArray);
};

horrible, but works for me.

Upvotes: 0

G&#244;T&#244;
G&#244;T&#244;

Reputation: 8053

You have two DOM elements with id=menu, a div and a ul.

<div id="menu"> <!-- <-- change this id for example -->
    <ul id="menu" data-role="listview" class="ui-listview " 
        data-bind="foreach: menu">
    ...
    </ul>
</div>

Ids should be unique, you need to change the id on one of your elements, hopefully this will also solve your problem.

Update

As you can read in this thread, ko.cleanNode will not remove items created using foreach binding.

You need to change your approach.

Here is a jsFiddle that reproduces your problem.

What you can do is stop cleaning+applying bindings, and update your observableArray instead:

$( document ).on( "pagebeforechange" , function(e, data) {
      var toPage = data.toPage[0].id;

     if( toPage == "home"){
         menuviewModel.menu.removeAll(); //clear menu
         //add whatever menu item you need
         menuviewModel.menu.push(new EditMenuViewModel("New Menu1 " + (new Date()).getTime()));
         menuviewModel.menu.push(new EditMenuViewModel("New Menu2 " + (new Date()).getTime()));
     }
});

function menuViewModel(){
    var self = this;
    self.menu = ko.observableArray([]);
    self.menu.removeAll();
    self.menu = ko.observableArray([
                    new EditMenuViewModel("Perfil"),
                    new EditMenuViewModel("Asignaturas")
                ]);
}

function EditMenuViewModel(name) {
    this.name = ko.observable(name);
    this.urlmenu = ko.observable("#"+name);        
};    

//bind only once
var menuviewModel = new menuViewModel();
ko.applyBindings(menuviewModel, document.getElementById('menu'));

Here is an example

Upvotes: 2

Related Questions