Component helper and stale data


#1

ember 1.11.0 ember-data 1.0.0-beta.15 ember-cli 0.2.0

In transitioning between routes it seems that my component is being initialized before the route has the correct data. When I click between items I’m seeing the data for the previous item being displayed by a nested component.

(not so) brief explanation: I have multiple Questions, each of which hasMany Options and hasMany Responses. I want to click through the Questions and display D3 charts based on the Options and Responses. The data I’m working with is an un-normalized mess and I can do nothing about it server-side. Each question’s options and responses come to me in its own unique, flaky format, requiring its own unique fiddling to make it useful. If I did this in the controller I’d need to create a masive switch statement. Instead, I created a separate component for each question. (There are only a dozen or so.) Each of these components molds the data accordingly, and each of its templates then loads the proper chart component(s) ie. histogram, bubble, etc.

The Question model has a computed property, chartType, which is the dasherized version of the Question’s “name” (FutureDemand -> future-demand). I’m passing that string to the new component helper. This almost works. The problem is that the component begins intializing before the route has fully transitioned, and so the fiddling on init is conducted on the previous question’s data.

I’m very new to Ember so I can’t be sure that the problem isn’t in the routing, or whether there’s a cleaner way to do what I’m trying to do.

BTW, this is a prototype only! I don’t plan to do anything remotely like this in production. The client understands that the entire data model will have to be redesigned from scratch.

Here’s the nutshell version:

Router.map(function() {
  this.resource('questions', function() {
      this.resource('question', { path: ':id' });
  });
});

var QuestionsRoute = Ember.Route.extend({
    model: function() {
        return this.get('store').find('question');
    }
});

var QuestionRoute = Ember.Route.extend({
    model: function(params) {
        // using fetchById because I don't want all related data
        // for index route -- far too much data
        return this.store.fetchById('question', params.id);
    }
});

var FooComponent = Ember.Component.extend({

    initData: function() {
        console.log('foo');
        // do stuff with options & data
        // this.set('stuff')
    }.on('init')
});

var BarComponent = Ember.Component.extend({

    initData: function() {
        console.log('bar');
        // do stuff with options & data
        // this.set('stuff')
    }.on('init')
});


// question.hbs
{{component model.chartType options=model.options data=model.responses}}

<!-- just to show we have correct data -->
<p>{{model.chartType}}</p>
<ul>
    {{#each option in model.options}}
    <li>{{option.id}}: {{option.label}}</li>
    {{/each}}
</ul>

The latter part of the template above always shows the correct data.

Going directly to /questions/1 (chartType = ‘foo’) I see this in console:

Preparing to transition from '' to 'questions.question'
Transitioned into 'questions.question'
foo

Clicking the link to transition to /questions/2 (chartType = ‘bar’) I see:

Preparing to transition from 'questions.question' to 'questions.question'
bar
Transitioned into 'questions.question'

The result is that the BarComponent receives the data for questions/1 instead of questions/2. If the templates for both components ultimately include eg. a histogram component then questions/2 will display the same chart as for questions/1, even though it displays the correct name & options in the parent template. If the two questions display different kinds of charts then I’ll get errors because initData is expecting a very different data format.