2

Is it possible to pull a simple JSON array from the server and use it as a "constant lookup table" in an Ember application?

I have a rails controller that returns a simple array of strings: [ "item one", "item two", "item three", ...]. I do not want them to to be full fledged Ember Models, nor do I want to represent them as an array of key:value pairs (ie, not [{name: "item one"}, {name: "item two"}, {name: "item three"}, ...])

How can I just pull the JSON array once, and reference that in my application?

To get started, I've tried just declaring a property on a controller that is then rendered in Handlebars by {{each}} tags:

controller:

window.App.SimpleController = Ember.Controller.extend(
  words: (() ->
    Ember.$.getJSON("http://localhost:3000/dictionary")
  ).property()
)

template:

{{#each words}}
    {{this}}
{{/each}}

Ember complains that this isn't an Array, but the jQuery promise object:

Uncaught Error: Assertion Failed: The value that #each loops over must be an Array. You passed {readyState: 1, getResponseHeader: ...

Which is confusing as well - I thought Ember handles promises as arrays?

Johnster
  • 133
  • 1
  • 7

2 Answers2

1

Ember handles promises returned to a model hook, not to a computed property. You'll either want to set it up in a route, or set up the computed property using a promise proxy.

The most common pattern is to fetch and set data in the route, but in the event where you want to do it as a computed property in the controller you can use the proxy pattern. Ember Data sets up their promise proxy using classes from Ember itself.

Your computed property could look like this if your response from server is an object:

words: (() ->
  var foo = Ember.ObjectProxy.extend(Ember.PromiseProxyMixin),
      promise = Ember.$.getJSON("http://localhost:3000/dictionary");
  foo.create({ promise: promise });
).property()

If your response is an array you would set up an array proxy

words: (() ->
  var foo = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin),
      promise = Ember.$.getJSON("http://localhost:3000/dictionary");
  foo.create({ promise: promise });
).property()

If it's an array there is another pattern of returning an array reference, then populating it later.

words: (() ->
  var foo = [],
      promise = Ember.$.getJSON("http://localhost:3000/dictionary");

  foo.then(function(data){ // this happens asynchronously
    data.forEach(function(item){
      foo.pushObject(item);
    });
  });

  return foo;
).property()

And then the easiest is to set the property during the route: EmberJS: How to load multiple models on the same route?

Community
  • 1
  • 1
Kingpin2k
  • 47,277
  • 10
  • 78
  • 96
  • Thanks, I'll try putting it in a route. Could you show an example of using a PromiseProxy? – Johnster Sep 09 '14 at 11:41
  • Nevermind I see you've done that here: http://stackoverflow.com/questions/20597087/how-to-return-a-deferred-promise-and-create-a-model-with-ember-deferred – Johnster Sep 09 '14 at 11:43
  • Looks like PromiseObject isn't a part of Ember DS any more? The docs seem to be woefully out of date with the code... – Johnster Sep 09 '14 at 12:57
  • 1
    Sorry, I typed the answer with my phone intending to get back to it and put in an example. Let me toss up some examples. – Kingpin2k Sep 09 '14 at 14:35
  • Super helpful explanation and great code examples. Thank you! – Johnster Sep 10 '14 at 16:09
1

you are corrected that ember handles promises as array but you need you return that array. i do not know rail syntax but regular syntax would be like this.

return Ember.$.getJSON("http://localhost:3000/dictionary").then(function(data){
     return data;
});

And this model should be in route, not controller.

Hope it helps!

LanNguyen
  • 234
  • 3
  • 15
  • Does that work since "data" is returned asynchronously? – Johnster Sep 09 '14 at 11:36
  • it should, getJSON returned a promise call. return only getJSON only will not do anything. The ".then" tells that once data is obtained from server, go ahead and return it. Handlebars is pretty cool, once the model is final returned it will update the html portion accordingly. – LanNguyen Sep 09 '14 at 21:47