Emberjs: Define model in Route - ember.js

I am trying to define a model in ember from a json object that does not conform to the JSON API standard. If I define my Route like
export default Ember.Route.extend({
model: function(){
var url = "http://website.com/prequalification";
return Ember.$.getJSON(url).then(function(data) {
return data.collection.template;
});
}
});
How do I then access my data in the template. I am trying to avoid writing a custom adapter to handle the JSON. Am heading down the wrong path here?
Thanks

When you navigate to the route which is using this route (you may need to familiarize yourself with the router and routes to understand that statement, http://emberjs.com/guides/routing/defining-your-routes/) the json returned by that model hook will be available in the template using standard handlebars syntax {{property}}
Here's a simple example, note the naming convention (index template, Index route): http://emberjs.jsbin.com/

Related

Proper way to set multiple models on route; depending on user authentication?

I'm currently working on an Ember app and it is coming along fine but since I am new to MVC applications in general there are a lot of concepts that don't come naturally to me.
I am currently trying to return two models for my index route. I referred to another SO question (EmberJS: How to load multiple models on the same route?) for the correct method and it has worked great.
My problem is now that I need to only set one of the two models only if the user is authenticated. I am using ember-simple-auth, and currently this is what I've got:
// app/routes/index.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
if (this.get('session.isAuthenticated')) {
var _this = this;
this.get('store').find('user', this.get('session.uid')).then(function(user) {
_this.set('model.entries', user.get('entries'));
});
}
return Ember.RSVP.hash({
newEntry: this.get('store').createRecord('entry', {
body: 'Write here ...'
})
});
}
});
For some reason, this does not work. After my route is loaded, the model only has the 'newEntry' property and not an 'entries' property, although the promise does get fulfilled (I put console.logs inside to prove it).
What could be happening? And is this the best way to accomplish this?
There is a set of data that you always want to load, for every user. Do that in the model hook, that is actually the data for the route.
There is another piece of info that you want to add only if a condition is met (authentication). Do that in the afterModel hook.
...is provided the route's resolved model...
http://emberjs.com/api/classes/Ember.Route.html#method_afterModel
So, now you can append or remove data from the model. Or take any relevant action depending on the data that you received.

Preload nested data with ember-data

In my Ember app, I have a nested hasMany relationships using ember-data like so workout->exercise->set.
My API has nested JSON instead of sideloaded JSON, so to fetch an existing workout I use store.find('workout', id) and override extractSingle.
My problem is when building a new workout I need to prepopulate it with exercises and sets based on a workout plan that a user is following. On the server side, I just have a /new controller action that prepopulates everything and renders a template.
Now that I'm moving to Ember I need the same functionality, but can't seem to make it work. The first thing I tried was to use Ember.$.getJSON to call a custom API endpoint in conjunction with pushPayload. This doesn't work however, because pushPayload bypasses extractSingle which means I can't convert my nested JSON into side-loaded JSON.
The prepopulation logic is very complicated so I'd prefer not to duplicated it client side and retrieve it from the API. Any other ideas on how I could accomplish this using ember-data?
For anyone trying to load embedded relationships with EmberData, check out EmberData's EmbeddedRecordsMixin.
Using Ember-CLI, you will need to create a serializer for the model with embedded relationships and add the mixin in the serializer like this:
// app/serializers/my-example-model.js
import DS from 'ember-data';
export default DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
Then, declare an attrs hash and include each embedded relationship with a hash for each, like this:
attrs: {
conference: { embedded: 'always' },
organizationType: { embedded: 'always' }
}
});
In my example above, conference and organizationType are both embedded in the myExampleModel model for both serializing and deserializing. That means that when I use this serializer over a RESTful API, I will get the embedded objects and I need to put the embedded objects.
The EmbeddedRecordsMixin has several options regarding each relationship, as in you have separate settings for serializing and deserializing. you can specify ids, records, or neither. embedded: always is shorthand for:
{
serialize: 'records',
deserialize: 'records'
}
It's all documented here with better examples here:
http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html.

How to structure a multi-record Ember app with named outlets?

I'm trying to build a Tweetdeck-like UI to arrange items from a central library into categories. I really need help wrapping my head around the canonical way of using Ember's router.
Essentially, I have a search UI, which allows the user to open zero or more categories simultaneously. The categories show a list of items, which the user can add to from a central library on the right. By completely ignoring the router and the URL, I have managed to hack together a semi-working proof of concept. Now I want to go back and try to do it the Ember way. Below is a high level sketch of what I am trying to accomplish:
If I understand correctly, the desired URL scheme would be a comma-separate list of model IDs that are currently open. I got a good idea of how to approach that from another question, How to design a router so URLs can load multiple models?.
Unfortunately, there are a few concepts I do not understand:
How do I construct my templates and router, such that the library is displayed with its own model and controller? I assume a named {{outlet}} is the way to go, but I am completely lost when it comes to the renderTemplate configuration. Or perhaps I should use {{render}} instead? In either case, I do not understand the router's role in this situation.
EDIT 1/28: I've added an updated fiddle that includes a standalone library route/template and documents my attempts to render it into the categories template. How does Ember expect me to give the library template its model when I try to embed it into another route? I've tried both {{outlet}} with renderTemplate and {{render}}, but in both cases, I am stuck when it comes to specifying the model.
Using renderTemplate:
App.CategoriesRoute = Ember.Route.extend({
renderTemplate: function() {
this.render('categories');
this.render("library", {
into: "categories",
outlet: "library",
controller: "library",
});
},
});
When my controller receives a request to open a category, how do I communicate that to the router? How is the hash path updated? Who is responsible for loading the appropriate model(s)? I assume I should start with transitionTo or transitionToRoute, but I do not understand the router's role here either. Specific questions:
How do I de-serialize multiple, comma-separated models from the URL? Do I just split on the comma or is there a better way?
Once I get the IDs from the URL, how do I make my model hook return multiple records? Do I just shove them all into an Ember array?
When the controller gets the ID of a new record to open, how do I communicate that to the router?
I've tried to work this out on my own and have read the Ember documentation many times, but I am afraid it is simply over my head. I put together a minimal (currently non-functional) fiddle to outline my thoughts and point out where I am stuck. I would appreciate any help anyone could offer.
this.render does not accept a model parameter, but you could pass the model through the controller property instead, this makes sense to do since the Controller is really a proxy for the model at any rate
App.IndexRoute = Ember.Route.extend({
var self = this,
notesController = self.controllerFor('notes').set('content', self.store.find('notes'));
renderTemplate: function() {
this.render('notes', {
controller: notesController,
into: 'index',
outlet: 'notes'
});
}
});
You could also try something like this from this link.
App.IndexRoute = Ember.Route.extend({
model: function() {
return Ember.RSVP.hash({
books: this.store.findAll('book'),
genres: this.store.findAll('genre')
});
},
setupController: function(controller, model) {
controller.set('books', model.books);
controller.set('genres', model.genres);
}
});
Here, they load multiple models into one route using Ember.RSVP.hash and then using setupController they set each model (Rails: instance variable?) individually.
I'm assuming using this method that you could load as many models as you needed.

Custom resolver to resolve model for /posts/create route

I am trying to use the resolver system to resolve a model for /posts/create.
My router mapping looks like:
this.resource('posts', function () {
this.route('create', {
path: '/create'
});
this.route('index', {
path: '/:post_id'
});
});
When I go to the /posts/1234 route, my resolveModel method on the resolver is called, but when I go to /posts/create, it is not. I'm assuming that I'm missing a naming convention here, but I want to get /posts/create to use the resolver rather than creating a PostsCreateRoute just to have a one liner in the model hook.
Any help would be appreciated. I'd love to know if I'm approaching this incorrectly as well. Thanks!
resolveModel is being called in the first route because ember has a special convention for routes that include path params that use the convention :model_id. When ember sees this it will try to find an instance of the model with the id of the path param. You can see this behavior here https://github.com/emberjs/ember.js/blob/master/packages/ember-routing/lib/system/route.js#L871-L888.
The second route has no path params so ember's default behavior is to do nothing. If you want to create a new instance of the post model when a user enters that url you will need to declare your own model function to perform this action. For example:
App.PostCreateRoute = Ember.Route.extend({
model: function() {
return this.store.createRecord('post', {});
}
});

ember-data findAll not working

I'm using the ember-data last version with an important problem I 'm trying to solve.
The find function by id works perfect and the proper record is loaded into the Data Store so I can obtain the attributes that I want in the template for render them.
App.PostRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('post', params.post_id);
}
});
On the other side, the findAll function doesn't work for me and the problem is Ember doesn't throw any error. In addition, Ember doesn't load any record and besides that I don't know how to iterate over the RecordArray returned in the template.
App.PostsRoute = Ember.Route.extend({
model: function() {
return this.store.find('post');
}
});
Any suggestions? Thanks for the help.
From your comment above, if your response looks like:
[
{"id":"1","attribute1":"value1", ...,"attributen": "valuen"},
{"id":"2","attribute1":"value1", ...,"attributen": "valuen"}
]
and you have not provided a custom serializer that modifies your response in extractArray(...), then data will not get processed because Ember Data expects something like:
{
"pluralizedModelName": [
{"id":"1","attribute1":"value1", ...,"attributen": "valuen"},
{"id":"2","attribute1":"value1", ...,"attributen": "valuen"}
]
}
See the Ember Data 1.0 specific code: https://github.com/emberjs/data/blob/master/TRANSITION.md#rest-adapter-and-serializer-configuration
How are you referencing the model in the template? Are you using the generated controller, or defining it yourself?
Also, the RecordArray should be automatically resolved by your Handlebars template. Try referencing {{#each}}. By default, your template will look for the property on the controller and if not found, bubble up to the model. If you can, create a JSBin (emberjs.jsbin.com) and we can collaborate with an example.
Edit: Also, are you using Fixture or Rest Adapter?