When using ember data are there any implications to fetching model data outside of a route? Or more specifically outside of a model hook?
For example say I have a complicated component and I pass in the store
, perform direct queries on the store
, and then handle the promises inside a function inside my component.
I am having a hard time using needs
api and am finding it easier to just pass along the store
and do lookups on the store directly.
I recognize this breaks some of the convenience of the router and model hooks. But I also am having a hard time finding good information and examples of managing dependencies between controllers using needs. What seems like it should be really obvious really isnât, at least for me.
1 Like
Iâm not fully aware of your context, but when Iâm faced with these sorts of problem, I tend to use the setupController hook to load my data from the store.
So, for example:
App.StandardRoute = Ember.Route.extend({
model: function(params) {
this.store.find('item', params.item_id);
},
setupController: function(controller, model) {
store = this.store;
store.get('thing').then(function(allThings) {
controller.set('allThings', allThings);
});
controller.set('model', model);
}
});
Perhaps this is nothing to do with what youâre talking about. I hope it helps.
3 Likes
Yeah. there are. For one, the router stops for promises, but only for certain hooks. These promise-aware hooks are âbeforeModelâ, âmodelâ, and âafterModelâ. Setup controller is not promise aware, and it is thus called after the model hooks have been resolved. You wonâ t be able to handle errors gracefully, and wonât be sure you have the right data at the right time, opening the doors to all kinds of timing-bugs. You wont enter error and loading routes unless you somehow tell it to, and you may also have to call the Run Loop manually to make sure all the bindings are updated.
The reason why this is such a pain lies in all those âmaysâ. This is one of of those emberisms of making your life complicated if youâre doing it wrong.
Really, you should try to be always fetching data from your model hooks.
What are you trying to use Needs for? Whatâs the use case?
1 Like
The promise stopping, loading and error substates some nice things about loading data in routes, but thereâs nothing inherently wrong with loading data elsewhere.
That said: I probably wouldnât pass the store around unless I had a really good reason to do so. Can you give us a simplified example of something youâre trying to do and Iâll see if I canât tell you how Iâd do it?
Every single time you call data from somewhere, youâre probably going to have to call the Run Loop to update your view bindings. Youâre not really supposed to be manually using the Run Loop, see the Guide: http://emberjs.com/guides/understanding-ember/run-loop/.
There is nothing wrong, but itâs taking the safety off. You should be using the model hooks to handle your data, and then let the Run Loop figure out the bindings. Once you step out of it, you have to call the run loop to update the view with your new ajax data. Of course, this is key to building real-time, data-intensive components in your app and opens up more advanced uses of Ember.
Thanks for this, man, Iâll definitely try transitioning the extra-data-loading code I have in my setupControllers to afterModel ASAP.
Iâm just wondering, though, have you any references to tutorials on this stuff at all? I wish there were a couple of medium-level Ember apps to study in the wild. (Like⌠having lists that load dynamically streaming from JSON, live filtering, and use things like setting required sets of data in addition to the main set of data - as is in the case of OP).
Most of the details are documented in the Guides, but really, no, there arenât many. Iâm making a series of screencasts called Ember Power Tools if youâre interested, its for mid to advanced ember devs.
Yeah, sounds cool! I think Iâm going to do a similar thing for maybe less advanced users.
@ulisesrmzroche can you provide an example of how @JulianLeviston setupController code would translate with the afterModel function?
@JulianLeviston @papagno, yeah no problem.
App.StandardRoute = Em.Route.extend({
model: function(params) {
// remember that this way of invoking store.find() has an implicit promise.
return this.store.find('item', params.item_id');
};
// the first param returns the value returned from model, or
// its resolved value if it was a promise.
// the second param is the transition object
// third param could be queryParams if you have that enabled.
// in this case, we don't care about any of that, because we're fetching a completely unrelated model, a hint that this may not be the best place to put this sort of logic.
afterModel: function(items, transition) {
var self = this;
return self.store.get('thing').then(function(allThings){
self.controller.set('allThings', allThings')
});
}
});
I think something like that may work but I gotta check a js fiddle or something. Iâd actually use controller needs for something like this though.
We all clear on needs and what they do?
1 Like
Actually, you know what, this is more of an SO type of question. Feel free to raise it over there and ping me when its up. @darthdeus has a post on controller needs here, Controller's Needs Explained - darthdeus' blog, in the meanwhile.
This is an awesome thread thanks for the replies. I would also like to see the stack overflow question so post a link if you can.
I have read the @darthdeus blog post. I think in my particular I must have been hitting a bug in my code.
But in general terms I have a single route that provides some highly dynamic search logic. And I would like to bring together three Array Collections on the same page.
I like what you are doing there with afterModel hook. It is giving me some ideas on how to tackle this.
Actually I posted on this forum here, with a link to a SO question.
@ulisesrmzroche it doesnât address the main issue, though, which is that the documentation doesnât have an example of this extremely common use case. Who do we talk to about getting the documentation changed once we have a canonical way of doing this?
If âneedsâ is the way to do it, then so be it, but how does he do it with needs? Please link us to something that explains that?
This is more than just a âhow do I do this in Ember?â kind of SO question, I feel, because itâs talking about addressing education of Emberâs canonical ways of doing really common things when developing a web app. Maybe it needs to be in the cookbook?
I totally agree with you, @JulianLeviston, and Iâve enjoyed watching you stir things up in the forum about it. I wish I could link you to a good example, but I donât think there are any.
What we need is an influx of high-quality in depth guides, tutorials, and especially screencasts, and yeah, we needed them like a year ago, but making those things can be harder than writing code, and thatâs why the sustainable ones are often paid ones, ei: railscasts, peepcode, manning, pragprog, etc. This is one of those very hard problems for any framework, even for the mature ones.
I should be more clear about my specific case. What I think I want to do it actually merge two types of models and display the combined values in a single template or component. I think this can be accomplished by a clever user of needs
and some computed
arrays. But let me illustrate with the psuedo code.
say I have two array collections and each contains a different type of model
array_of_foos = [ {foo:"123"}, {foo:"456"}, etc...]
array_of_bars = [ {bar:"abc"}, {bar:"xyz"}, etc...]
merged = [ {foo: "123", bar: "abc"}, {foo: "456", bar: "xyz"}, etc...]
What I want to do is conveniently display these merged models in my view template e.g.
{{#each item in merged}}
{{ item.foo}} and {{item.bar}}
{{/each}}
each foo has an id and each bar has an id, so the identity map should just work.
I feel like this can be accomplished with some clever use of computed properties
and needs
but the specifics are lost on me at the moment.
I suppose the other approach here is to create basic ember objects in the afterModel
hook.
Thoughts?
@ulisesrmzroche I think I am clear on needs
.
But what is not clear to me is the route step. If you have controller A that needs controller B and you never travel to route B how can you fetch the data associated with B from within the context of controller A programmatically? Is this what setupController is suppose to do?
Here is a simple example jsbin and ember appkit rails (es6 modules)
http://emberjs.jsbin.com/gibanihu/2/
https://github.com/eccegordo/circle_square
What trips me up is the fact the controller referenced from the other controller will have no data, at least initially, until you click around the routes and populate the controllers.
How do I work around this issue? beforeModel
?
@eccegordo, you can use this.generateController on your route if you need to generate one by hand. You can then seed the controllers, whether its on the route or maybe right on the controller. Iâd do it on the Route Level, sometime around beforeModel â afterModel.
Like, thereâs really nothing to penalize you from using model for anything other than data, but I think there should be. Its best leaving that hookâs concern to only be fetching and initializing data, and handle any other behaviour in afterModel or beforeModel.
@matthooks
Here is a stripped down jsbin that I think illustrates the basic problem I am trying to solve. It seems like this should be trivial to implement but I keep fighting the ember router. Or else the advance cases are just not well documented with clear code examples. My more cynical self says that there is a lot of cargo culting around the router within the community. I am fully sympathetic to the general principle of the router first design. But it seems like it shouldnât be so $@#!*% hard. But I will be the first to admit I am an idiot and probably just donât get it.
Basic problem:
I have a âsearchâ route/view/controller that I want to implement all my search logic. And display the results in place. This search view depends on multiple controllers and parts of the system.
http://emberjs.jsbin.com/haculimi/2/
@ulisesrmzroche
I looked at the api guide for generateController
using a private method seems a little overkill? I guess I would need to see a code example. Thanks for the feedback.
Are you expecting the actual search to take place on the client or the server?