gmac / backbone.epoxy

Declarative data binding and computed models for Backbone
http://epoxyjs.org
MIT License
615 stars 89 forks source link

dependency-mapping not working as expected for computeds in a view #34

Closed bbn closed 10 years ago

bbn commented 11 years ago

I have created three computeds in a view. I expect that when I call "setBinding" to set either of the first two, that the third will recompute automatically via automatic dependency mapping. However that doesn't happen -- the only time this dependent property is computed is when the view is first created.

Here's my coffeescript code:

computeds: 
  focusDate:
    set: (d) -> @focusDate = d
    get: -> @focusDate

  league:
    set: (l) -> @league = l
    get: -> @league

  previousPeriodLink: ->
    focusDate = @getBinding "focusDate"
    league = @getBinding "league"
    console.log "meep" # to test if it gets called more than once
    return "#" unless focusDate and league
    previous = moment(focusDate).subtract('days',1)
    "#{league.get "abbrevation"}/#{previous.getFullYear()}-#{previous.getMonth()+1}-#{previous.getDate()}"

And below is the compiled javascript, in case that's preferable:

CalendarView.prototype.computeds = {
  focusDate: {
    set: function(d) {
      return this.focusDate = d;
    },
    get: function() {
      return this.focusDate;
    }
  },
  league: {
    set: function(l) {
      return this.league = l;
    },
    get: function() {
      return this.league;
    }
  },
  previousPeriodLink: function() {
    var focusDate, league, previous;
    focusDate = this.getBinding("focusDate");
    league = this.getBinding("league");
    console.log("meep");
    if (!(focusDate && league)) {
      return "#";
    }
    previous = moment(focusDate).subtract('days', 1);
    return "" + (league.get("abbrevation")) + "/" + (previous.getFullYear()) + "-" + (previous.getMonth() + 1) + "-" + (previous.getDate());
  }
};
bbn commented 11 years ago

just wanted to also note that I tried explicitly declaring the deps, and that also didn't work.

gmac commented 11 years ago

Thanks for the report... I'm trying to catch up on bugs this week. Will look through the issue and follow up.

gmac commented 11 years ago

Ah, I know what the situation is here... the View getBinding method is really just a pass-through accessor for assembling data from some underlying model attribute. View computeds will change in response to their underlying models changing, but not to each other changing. This is admittedly confusing and unexpected, and definitely works different from model attributes. Let's call this a bug and slate it as a major future development item.

bbn commented 11 years ago

Great Greg, thanks. Perhaps it's something I can contribute? Modify view computeds so that they are aware of each other?

Is there a reason why getBinding was used as the accessor method name rather than get?

On Mon, Sep 9, 2013 at 4:05 PM, Greg MacWilliam notifications@github.com wrote:

Ah, I know what the situation is here... the View getBinding method is really just a pass-through accessor for assembling data from some underlying model attribute. View computeds will change in response to their underlying models changing, but not to each other changing. This is admittedly confusing and unexpected, and definitely works different from model attributes. Let's call this a bug and slate it as a major future development item.

Reply to this email directly or view it on GitHub: https://github.com/gmac/backbone.epoxy/issues/34#issuecomment-24110145

gmac commented 11 years ago

Relevant documentation on this discussion (I'd forgotten this point myself):

"A hash table defining a view's computed properties. Computed view properties act as custom data routers: they assemble custom values from data available in the binding context, and route formatted values. While this is conceptually similar to computed model attributes, computed view properties are unique in that they do not store their own data, nor do they trigger any events; they simply act as pass-throughs for modifying context data using the view's getBinding and setBinding API methods. Computed view properties are an excellent place to assemble view-specific display values and/or markup.

Computed view properties may be declared with a computed params object, or as a getter function (uses automatic dependency mapping). Computed view functions are called in the context of the view, so referencing this refers to the parent view."

From http://epoxyjs.org/documentation.html#view-computeds

RE: the getBinding method name was selected to harmonize with other popular Backbone tools, and also to differentiate its behavior from the Model get method, which stores data and triggers events. Now that I'm thinking about it, the difference in naming had a lot to do with the unexpected functionality of your original report.