change event on compute of a List

75 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 answers

0
nick lang 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
Justin Meyer 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.