I'm trying to have a route's model hook return some array that is constantly updated via a polling mechanism using Ember later
. The route file looks like this:
export default class IndexRoute extends Route {
recent: [],
init() {
...
this.getRecent();
}
getRecent() {
// poll data / fetch latest
this.recent.push(newStuff);
later(this, this.getRecent, 2000);
}
model() {
return this.recent;
}
}
Then in my controller, I wanted to create a @computed
/ @tracked
property based on the route's model
:
export default class IndexController extends Controller {
// @tracked model; // this also didn't work
@computed('model.@each') // this doesn't work
get computedModel() {
console.log('computedModel'); // prints only once, when the model hook is first run
return this.model;
}
}
I thought what this SO post suggested would have worked but it didn't :(
I saw this post but this was for Ember 1.13 so not exactly a modern solution.
Similarly this post had outdated content too.
Is what I'm trying to do possible? Alternatively I was thinking of moving the data into the Controller and making a computed property of a Controller variable instead. Taking all suggestions!
The fundamental problem with your current approach is that you are not using Ember Array specific functions. There is often some magic that happens when you create arrays in Ember that automatically creates them as Ember arrays (at least this was the case when using the old style syntax with
.create
and when prototype extensions were allowed). You can always explicitly create an Ember array with:Anyway, when you just use
this.recent.push(newStuff);
, this native array prototype is not instrumented in a way that Ember's tracking/observer system can know that the a new value has been added tothis.recent
and subsequently trigger a rerender. This applies to both tracked properties as well as the traditional observer system pre-Octane.Instead, when interacting with arrays that are being displayed in templates (ie arrays that need to be observed), you must use special
Ember.Array
specific functionspushObject
likethis.recent.pushObject(newStuff)
.If you wanted to go full on tracked property style, you can avoid using the Ember array, but you must force a recompute by reassigning the array to the tracked property. Here's an example in a component
Here is a Ember Twiddle that shows both approaches in action.
PS. The
model
property of a route is only quasi-dynamic. During the transition, the return value of themodel
hook is automatically assigned to the route'scurrentModel
property. This value is then passed intosetupController
as the second parameter and automatically assigned to the controller'smodel
property if nosetupController
is defined or if thesetupController
invokessuper
of the base implementation. WhenmodelFor
is called for a particular route, thecurrentModel
property is returned andmodel
is not reinvoked. This is all to say that having the poll in themodel
function itself would not automatically update the controller'smodel
property. Everything works fine in your example since themodel
reference never changes (you're just mutating the array).