I am New Ember.js and Ember-Data. With some sample tutorials I was able to understand a few basic things and started to right my own application. Now I am facing a problem, where I'm supposed to call two different REST services: one to display the table value in hbs and another to load data to a drop down select box in my Route, but I couldn't achieve this.
I tried most of the approaches given in blogs, but I can't find a solution. Can you please guide me on this?
Approach
model : function() {
return this.store.find('User');
},
customers: function(){
return this.store.find('Customer');
},
Error I Got
Error while processing route: AdminUser Assertion Failed: The response from a findAll must be an Array, not undefined
The error you're seeing appears to be an issue with your API response. It's saying that it's returning a single user object as opposed to an array of users.
Once you've got that resolved, you can use Ember.RSVP.hash to return a collection of promises that must all be resolved for the model to be considered resolved. Then use setupController to set the users as the model, and customers as a separate property on the controller.
model : function() {
return Ember.RSVP.hash({
users: this.store.find('User'),
customers: this.store.find('Customer')
});
},
setupController: function(controller, model) {
controller.set('model', model.users);
controller.set('customers', model.customers);
}
Related
I'm getting some curious behaviour that I can't figure out the reason for.
This is my router:
App.Router.map(function() {
this.resource('mapPieceSets', { path: '/map-pieces' }, function () {
this.resource('mapPieceSet', { path: '/:mapPieceSet_id' }, function () {
this.resource('mapPiece', { path: '/:mapPiece_id' });
});
});
});
I reload the app from the home page #/ then navigate down to the mapPiece route, I get these URLs requested:
[Domain]/api/mapPieceSets/
[Domain]/api/mapPieces/1/
[Domain]/api/mapPieces/2/
And it all works fine (mapPieceSets returns a list of mapPieceSet which have a list of mapPiece against them)
However, if I reload the whilst on a mapPiece routed page, then I get this URL:
[Domain]/api/mapPieceSets/
[Domain]/api/mapPieceSets/?mapPieceSet_id=1
[Domain]/api/mapPieces/?mapPiece_id=1
So switching from /:id= to ?id=, which isn't working on my end points (that's a side issue which I need to resolve), but just wondering why the URLs changed what they're requesting, and why we get a request to mapPieceSets/?mapPieceSet_id=1 when the whole of that object is returned within the response from mapPieceSets/
(If you need any other snippets of code from my app, let me know and I can put them in)
This is a fairly common confusion. When you're in your app navigating around you're often using a link-to which is then telling ember to use the specified model when visiting the route. When you're refreshing the page, Ember has to divine the models using the url /apimapPieceSets/3/2. At that point it will go to each route MapPieceSetsRoute, MapPieceSetRoute, and MapPieceRoute and hit each model hook passing in any associated params. So what you need to tell Ember how to do, is how to load a mapPieceSet, and mapPiece properly. You'll need to setup a model hook for both of those.
App.MapPieceSetsRoute = Em.Route.extend({
// I don't know if you're using Ember Data, but I'm going to assume you are
model: function(params){
return this.store.find('mapPieceSet', params.mapPieceSet_id);
}
});
From what you said, it sounds like the model is already available client side from the mapPieceSets. In that case, you can use the modelFor method to get a parent's route's model and get your model.
App.MapPieceSetsRoute = Em.Route.extend({
// I don't know if you're using Ember Data, but I'm going to assume you are
model: function(params){
return this.modelFor('mapPieceSets').get('properyWithMapPieces').findBy('id', params.mapPieceSet_id);
}
});
I'm currently using EmberJs along with Ember-Data to build an app backed by a Laravel JSON api.
I got a little issue on the saving process, mostly on model creation.
Here is my workflow :
The Ember ObjectController saves itself this.get("model").save()
Laravel (REST api) receives the data and persist it, therefore
creating a unique ID for it
The api return the new data (that
respect Ember convention) with the proper ID
???? Ember-Data doesn't
seems to care about the response since it does nothing...
The problem here : the id remains undefined even if it has been given...
The workaround I found is to reload models... but it's a big performance flaw considering that the data I want to be reloaded it available to Ember straight after the save()
any ideas ?
EDIT **
The problem only occurs on the first object that I add. When I repeat the process the next objects are refreshed correctly. If I hit refresh, it start again : the first object miss his refresh and the following are okay.
Here my code about the add process :
route
App.CategoriesNewRoute = Ember.Route.extend({
model: function()
{
return this.store.createRecord("category").set("active", true);
},
setupController: function(ctrl, model)
{
ctrl.set("errors", 0);
ctrl.set("model", model);
}
});
I don't have any Router for CategoriesRoute since the data is all in my ArrayController from the start.
controller
App.CategoriesNewController = Ember.ObjectController.extend({
needs: "application",
actions:
{
save: function()
{
this.get("model").save();
this.get("target").transitionTo("categories");
},
cancel: function()
{
this.get("model").rollback();
this.get("target").transitionTo("categories");
}
}
});
EDIT ** 2
I tried the code provided below with no success...
I added 2 records, and the first don't have it's ID... the second got it, so the problem appears to only be on the first save...
Here are the 2 responses I got from my API
ObjectA
{"category":{"nameFr":"aaa","nameEn":"aaa","active":true,"id":10}}
ObjectB
{"category":{"nameFr":"bbb","nameEn":"bbb","active":true,"id":11}}
It could be because you're transitioning before the save finishes, and so the model hook on the categories route fires while the model you're saving is still in flight (are you getting any errors in the console?). Try changing the save action to
save: function()
{
var that = this;
this.get("model").save().then(function(){
that.get("target").transitionTo("categories");
});
},
Also, you don't need to this.get('target')... as there's a controller method transitionToRoute. You can simplify to:
save: function()
{
var that = this;
this.get("model").save().then(function(){
that.transitionToRoute("categories");
});
},
Found that the problem seems to be on Ember-Data's side...
documented the whole thing here :
http://discuss.emberjs.com/t/missing-id-on-first-save-on-a-new-object/4752
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.
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?
I have a two page Ember.js application using ember-data to wrap a simple RESTful API. The main page is a list of products, and the other page is a product details page for one product. The data is loaded via an API that only has an "index" request, /api/products.
The above works fine when navigating the site via the main page, however I'm not sure how best to handle navigating directly to the product details page. I need ember-data to request all products and keep these products client-side so that as the user navigates the simple site it doesn't make any more requests back to the API for products. However, the ProductIndexView and ProductIndexController in my application should preferably only see the one record.
Is there a good way to handle this in Ember.js? I know that I could add a computed property to the controller that filters down the full list and then pass that into the view template. However, I'd rather the view and controller not know about the full list.
You need to nest all your routes in a resources that fetches all products.
Something like this:
App.Route.map(function() {
this.resource('products', { path: '/' }, function() {
this.route('index');
this.resource('product', { path:'/:product_id'} );
});
});
App.ProductsRoute = Ember.Route.extend({
model: function() {
return App.Product.find({});
}
});
App.ProductsIndexRoute = Ember.Route.extend({
model: function() {
return this.modelFor('products');
};
});
Use the products/index template to display all products.
Use the product template to display a product detail.
Notice the {} I included in App.Product.find({}). This enforces ember-data to return a promise. This is necessary to make the product route wait for all products to arrive from the server before being called.