Tracking list overlaps in knockoutjs

Go To StackoverFlow.com

0

I have an application where objects might be in one of several lists. The UI for one list needs to mark each item as being on one of the other lists.

A grossly simplified version of what I've implemented is this:

function Item(id, panel) {
    var that = this;
    this.id = id;
    this.viewModel = panel;
    this.isSelected = ko.computed(function(){
        return panel.isSelected(that);
    });
}

function Panel() {
    var that = this;

    //my two lists
    this.all = ko.observableArray();
    this.selected = ko.observableArray();

    this.isSelected = function(item){
        return _(that.selected()).find(function(thing){
            console.log("iterating");
            return thing.id == item.id;
        });
    };
}

var panel = new Panel();
ko.applyBindings(panel);

//add some things to the list
for(var i=0; i<40; i++){
    var item = new Item(i, panel)
    panel.all.push(item);
    //let's select some of them. note it's actually a different object
    if (i % 2 == 0){
        panel.selected.push(new Item(i, panel));
    }
};
​

Fiddle is here: http://jsfiddle.net/89j52/5/

So, beyond the weirdness of giving the item a reference out to the panel, it also performs terribly. That's because every time you add another item to the selected list, it recomputes the selected status for all the items; notice how many times it prints "iterating". I understand why it's doing that, but it's painful.

Now obviously, it doesn't really need to check every item each time I do an add. I could, for example, stash a lookup table for the items and then just update the right ones when something gets added to the selected list. But I'm not sure how to marry that to Knockout's observable/computed stuff and make the UI update seemlessly. How should I tackle this within Knockout's idioms?

2012-04-03 23:04
by NoName


1

What if you convert isSelected to regular observable (not computed) and update it directly every time you add item to selected list:

function select(item){
    panel.selected.push(item);
    var itemInAll = _(panel.all()).find(function(thing){
        return thing.id === item.id;
    });
    itemInAll.isSelected(true);
}

Not very elegant, but definitely more efficient. You don't need to keep a reference to panel in Item, too. Here is the full code: http://jsfiddle.net/89j52/9/

2012-04-04 13:51
by Roman Bataev
I ended up doing something along these lines. I'd still like something slicker, but it works fine - NoName 2012-04-12 14:06
Ads