I was looking for a mechanism to update the route model and has a component (called from the template associated with this route) that responds to this event and re-renders.
So, I have an index template like this (I go through the IndexController model, which, as I understand it, is just an IndexRoute proxy server - by the way, I don't have an IndexController pointer):
<script type="text/x-handlebars" id="index"> Below is the bar-chart component <br/> {{bar-chart model=model}} </script>
And I have my component template as follows:
<script type="text/x-handlebars" data-template-name="components/bar-chart"> </script>
My component is implemented in a separate JS file, for example:
App.BarChartComponent = Ember.Component.extend({ classNames: ['chart'], model: null, chart: BarChart(), didInsertElement: function() { Ember.run.once(this, 'update'); }, update: function() { var data = this.get('model').map(function(sales) { return sales.get('amount'); }); d3.select(this.$()[0]).selectAll('div.h-bar') .data(data) .call(this.get('chart')); } });
The BarChart () function simply returns a function object that performs DOM manipulation to generate a chart using D3.
My IndexRoute is defined as follows:
App.IndexRoute = Ember.Route.extend({ model: function() { return this.store.find('sales'); } });
During this experiment, I use fixture:
App.Sales = DS.Model.extend({ amount: DS.attr('number') }); idx = 1; App.Sales.FIXTURES = [ {id: idx++, amount: 2}, {id: idx++, amount: 6}, {id: idx++, amount: 12}, {id: idx++, amount: 17}, {id: idx++, amount: 8} ];
I need to implement a mechanism for periodically polling the store and updating the route model, and the magic of EmberJS will call the rendering function again (the value assigned to the "chart" field in the BarChart component).
What is the right way to do this? I tried to use setInterval and call the refresh () method of the Route, but have not been successful so far.
Thanks for your help !, Raka
ADDITIONAL INFORMATION (I added here an additional comment for formatting).
I added a setInterval call to my app.js, for example:
setInterval(function () { App.Sales.FIXTURES.shift(); App.Sales.FIXTURES.push({ id: idx++, amount: Math.round(Math.random() * 20) }); App.IndexRoute.refresh(); }, 1500);
But I get a JavaScript error telling me that App.IndexRoute is undefined. I intend to call the refresh method on the Route object because I hope that the model interception will be re-executed. How to get a reference to an IndexRoute instance from my setInterval function?
Is this the right / best way to start updating, btw?
(and following Oliver’s suggestion below, I also added observers (“model”) to my “update” function in the controller. So now it looks like this:
App.BarChartComponent = Ember.Component.extend({ classNames: ['chart'], model: null, chart: BarChart(), didInsertElement: function() { ... }, update: function() { ... }.observes('model') });
ADDITION 2 (response to EmberJS, polling, updating the route model, re-rendering component )
Got! thanks.
Now for the option to use the update (the number of elements in the backend remains the same, the identifiers remain unchanged, only the "amount" changes over time). I changed setInterval to this block:
setInterval(function () { App.Sales.FIXTURES.forEach(function(elem) { elem.amount = elem.amount + 5; }); console.log('z'); }, 1500);
Now the problem: the “update” method in BarChartComponent, which observes “model. @ Each”, is never called (as if the changes I made in the elements of the device were not heard by BarChartComponent).
What instructions need to be added?
ADDITION 3 (more for EmberJS, polling, updating the route model, re-rendering component ):
I added an IndexController definition to my code to confirm that my changes to the elements in FIXTURE were heard, at least by the controller (it is).
So now the problem is that this change is also heard by the Component. How? Do I have to call some "render" function from my controller to ask the component to redraw itself?
App.IndexController = Ember.ArrayController.extend({ totalAmount: function() { console.log("iiii"); var total = 0; this.forEach(function(sales) { console.log("a... " + sales.get('amount')); total += sales.get('amount'); }); return total; }.property('@each.amount') });