Request models outside of route or model hook

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?