Loading new records


#1

I’m trying to do something that seems extremely simple.

I have a route like this:

App.FoosIndexRoute = Em.Route.extend({
  model: function() {
    this.store.find('foo');
  }
});

The view for this is simply a list of the models. If I then, say, create a new item via a curl to my API, and navigate away from and back to this view, I expect it to be easy to update the store with the new records that were created, and have the view update automatically as a result.

As far as I can see (based on the convoluted solutions suggested to others on Stack Overflow), this is actually super complex and non-trival with Ember Data. Am I totally missing something?

  • Ember v1.5.1
  • Ember Data v1.0.0-beta8

#2

Actually, that should just work. Can you pass a link to those answers on SO?


#3

@ulisesrmzroche Whoops, my route was actually this:

App.FoosIndexRoute = Em.Route.extend({
  model: function() {
    return this.store.find('foo');
  }
});

I expected this to work, but apparently this.store.find isn’t resolved until actual API calls are made. The following has the expected behavior:

App.FoosIndexRoute = Em.Route.extend({
  this.store.find('foo');
  return this.store.all('foo');
});

However, it seems odd that I should have to do this. Also odd is that this.store.find triggers an API call every single time (which is actually desired in my case), but according to the guides, this shouldn’t be happening.


#4

The thing is that return this.store.find('foo') should be all you need to do and everything should be wired up right. Have you tried fiddling with setupController?


#5

@ulisesrmzroche Here’s a Runnable that illustrates the problem: http://runnable.com/U45VgeXUy4o_d_Zw/ember-data-issue-for-jquery-and-javascript


#6

I don’t really understand what’s coming back from your REST endpoint, which might help a little bit. To @ulisesrmzroche 's point, does something like this do what you’re looking for?

App.FoosRoute = Em.Route.extend({
  setupController: function(controller, model) {
    this.store.find("foo").then(function(foos){
      controller.set("model", foos);
    });
  }
});

#7

I think this is what you want, check the structure out. Only thing is that it is slow as balls, give it a few seconds for the server to come back with the results. maybe runnable runs faster but I couldn’t figure it out fast enough.

http://emberjs.jsbin.com/sekix/12/


#8

It’s just a dummy API I built specifically for this, and there’s a two-second timeout on the server in order to force some latency. The first request should take two seconds. Subsequent transitions to this route should be (near) instantaneous because of the cache.

Both of these solutions do not make use of the fact that the first request stores the records in the store, so the caching there is completely wasted.

It’s amazing to me that this isn’t very trivial:

  1. Do the first request. It takes 2 seconds because the server is (intentionally) slow.
  2. Click the “Home” button.
  3. Go back to the page that does the request. It is instantaneous, but will update if any new records come back in the API request (which it performs after the transition/render has already happened).

@ulisesrmzroche Specifically, that JSBin waits until the API request completes on every request, regardless of the fact that it has some records in the store already, if it’s already been performed once.

My solution above seems to be the only way to do it: return this.store.all('foo') as the model (which resolves immediately if there are already records in the store). Call this.store.find('foo') beforehand, as well, so that the model is updated with any new records when that request completes. This seems contrary to the Ember Data documentation, is this really not a common use case?


#9

Actually, .find returns a promise, and .all() grabs the ones in the cache. I think that part of the guide is out of date. To support your first use case, the jsbin should be all you need. Try going to the home route, then making a new record on the API, then going back to the foos route.

If you don’t want to waste a GET request, then you’ll have to tell Ember that you have new data somehow else. You can try either websockets and pushing data into your app, or preloading the data somewhere else in the app, (most folks use ApplicationRoute).


#10

I actually want to make the GET request every time I enter the route, but if there’s a cached version available, I want to enter the route instantly (i.e. before the request completes), render the cached version, and then update the view once the API request completes. .find doesn’t solve this problem. Using .all in combination with .find kind of seems to, but it feels like a hack for a very common scenario.


#11

How about taking out the fake latency?


#12

Doesn’t feel like a hack to me, you have to load data into the store before ember can know about it. How about the case when the user reloads the page? How can you render a cached version then?


#13

The fake latency is there to simulate an app with greater latency, it’s just easier to test this. If I got rid of it, it’d be more difficult to tell whether or not any given approach is working. If caching is working properly, toggling between “Home” and the “Foos” route should be instantaneous after the first API request has been completed.

If it’s a full page reload, I obviously wouldn’t expect to render a cached version. I would, however, expect for it to be easy to render the cached version on subsequent renders of that view, perform the API request in the background, and then update the view with new records.

Instead, for every single route in my apps, I have to manually check to see if record(s) exist in the store. If they do, I can trigger an API request and immediately render. If they do not, I have to return the API request’s promise. This pattern is totally fine—it’s just surprising that for such a simple use case, there’s not an obvious solution.