Question

Two attributes in my model are supposed to update each other when changed, once. The startDate and endDate. Their values are Moment objects, from the moment.js library.

Two Moment objects of identical dates are not equivalent, and so this causes an loop that exceeds the maximum stack, because they appear to Backbone to have always changed.

new moment('01/01/12') == new moment('01/01/12') // => false

The { silent: true } option seems not to help, I think because it only defers the change event rather than suppressing it alltogether, though I'm not sure.

Here's the code that overflows:

class Paydirt.Models.BlockBrowser extends Backbone.Model
  initialize: =>
    @on('change:startDate', @updateEndDate)
    @on('change:endDate', @updateStartDate)
  
  updateStartDate: =>
    @set({ startDate: @cloneEndDate().subtract('days', @get('interval')) }, { silent: true }         

  updateEndDate: =>
    @set({ endDate: @cloneStartDate().add('days', @get('interval')) }, { silent: true } ) 

  cloneStartDate: => new moment(@get('startDate'))
  cloneEndDate: => new moment(@get('endDate'))

I can set a global flag to prevent the callback loop as in this variation:

  updateStartDate: =>
    if !@changing
      @changing = true
      @set({ startDate: @cloneEndDate().subtract('days', @get('interval')) }, { silent: true } ) 
      @changing = false
        
  updateEndDate: =>
    if !@changing
      @changing = true
      @set({ endDate: @cloneStartDate().add('days', @get('interval')) }, { silent: true } ) 
      @changing = false

... but this is obviously a hackety solution. Is there a better pattern for me to follow in this use case?

Thank you.

Was it helpful?

Solution

Another idea:

Are you using Backbone v0.9.2? it looks like it is doing a more intensive use of the options.silent. Look here.

The options.silent behavior you're describing looks more like v0.9.1.

OTHER TIPS

Two ideas:

  1. Overwrite the Underscore method _.isEqual to manage properly your Moment objects. You can use the Proxy pattern.

  2. Use custom events to have more control that when they are triggered.

I'm not sure how to do this in backbone, but you can compare the integer value of the moments

(moment().valueOf() === moment().valueOf()) // true

or

(+moment() === +moment) // true
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top