change event on compute of a List

96 Views Asked by At

I have a Map like so:

var AppState = can.Map.extend({
  sites: null
});
appstate = new AppState();

the list gets populated like this:

Site.findAll({}, function(sites) {
  appstate.attr('sites', sites);
});

which I pass to a control like this:

new SummaryCtrl("#summaryCtrl", {sites:appstate.compute('sites')});

The control looks like this:

var SummaryCtrl = can.Control.extend({
  '{sites} change': function(ev, type, sites) { //this doesn't fire
    var recent = sites.slice(0,25);
    var siteCount = sites.length;
    this.element.html(can.view('summaryTpl', {siteCount:siteCount, recent:recent}));
  }
});

Then I do this:

var newsite = {blah1:'blahblah', blah2:'blahblah'};
appstate.sites.unshift(newsite);

But the '{sites} change' function doesn't fire. Any idea why? Thanks!

2

There are 2 best solutions below

0
On

Figured out a solution - not sure if its the best solution, but its ok for my use.

I realized a compute of a list does not have the same interface as the list. Intuitively, I thought it would. So instead of passing a compute of the list to a control, just pass the list itself and use .replace and .unshift on the list as needed.

If you need to use a map, that is fine, but again, don't pass in computes of the properties on the map, just reference the property itself and initialize as an empty list like so:

var State = can.Map.extend({
  sites: new can.List()
});

http://jsfiddle.net/c7tdma5k/25/

0
On

The reason this doesn't work is because the compute only changes when the sites property changes, not the individual items in sites.

If you created the compute like:

var sites = can.compute(function(){ var sites = appState.attr("sites"); sites.attr("length") return new List().replace(sites) })

This would work. The compute would change anytime an item was inserted or removed in the list. However, your answer is a better way of doing this.