Ember dynamic segment with parameters - ember.js

I have a dynamic segment route like this -
#resource 'owners', { path: "/:owner_id"}
#resource 'product', { path: "products/:product_id" }
Product route needs information from this route, and needs to load after some product params are loaded
Market.ProductRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('product', params.product_id);
},
afterModel: function(model){
this.store.find('owner', model.get('id'), { 'owner_type':model.get('owner_type')});
},
});
And I get the following errors:
Error while processing route: product Assertion Failed: metaForProperty() could not find a computed property with key 'owner_type'. Error: Assertion Failed: metaForProperty() could not find a computed property with key 'owner_type'
Error: More context objects were passed than there are dynamic segments for the route: error
Uncaught Error: Assertion Failed: Error: More context objects were passed than there are dynamic segments for the route: error

Looking at your code, I think your intent is to load the associated owner after you load the product. I'm also assuming that you want to send the product id and owner_type to your server because this is a polymorphic relationship.
You're getting the error about owner_type error because you're passing something really weird as the third argument to find which is reserved for indicating data and relationships that you know are already preloaded -- probably not what you want. I can't help but notice the mix of CoffeeScript and JavaScript. It makes me think that you're mistaken about how find works because you're used to having CoffeeScript gather all the key-value pairs that you pass to a function into one object literal.
The second error More context objects were passed... is probably because you have a link where you're passing objects to a {{link-to}} helper when there isn't a dynamic segment (or not enough dynamic segments) in your router path. This is hard to tell from just the posted code.
Here is what I think you want to do in your product route:
Market.ProductRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('product', params.product_id);
},
afterModel: function(model) {
this.store.find('owner', {
owner_id: model.get('id'),
owner_type: model.get('owner_type')
});
},
});
If you have control over your API it might be nice to just include the owner when you search for the product. I've had applications where sometimes I want associations and sometimes I don't. I often end up with routes that look like this:
Market.ProductRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('product', {id: params.product_id, include: ['owner']});
}
});
At that point your server would take this {include: 'owner'} data to mean that it should also return the owner as side-loaded data.
Hope something in there helps!

Related

Ember Rest Adapter - How to Call two rest services on single route

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);
}

Query-params-new nested routes strange error

In an application I use the latest canary versions for Ember and Ember Data. I have the following router:
this.resource('articles', {path: '/articles'}, function() {
this.resource('article', {path: '/:article_id'});
});
In the ArticlesController I specify some queryParams:
queryParams: ['category', 'search'],
category: '1', // defaults to 1
searchTerm: "",
In my ArticlesRoute I specify a model refresh and the model:
queryParams: {
category: {
refreshModel: true
}
},
model: function(params) {
// here I do use the params to return articles based on category and/or searchTerm
}
So far so good, all code above works perfect. However when I do a this.transitionTo('article', articleObject) or this.transitionToRoute('article', articleObject) in my application I get the following error:
Error: You didn't provide enough string/numeric parameters to satisfy all of the dynamic segments for route article
at Object.__exports__.default.subclass.createParamHandlerInfo (http://localhost:8000/vendor/ember/index.js:44242:21)
at Object.__exports__.default.subclass.applyToHandlers (http://localhost:8000/vendor/ember/index.js:44121:37)
at Object.__exports__.default.subclass.applyToState (http://localhost:8000/vendor/ember/index.js:44088:21)
at Object.Router.transitionByIntent (http://localhost:8000/vendor/ember/index.js:43312:33)
at Object.Router.refresh (http://localhost:8000/vendor/ember/index.js:43459:21)
at EmberObject.extend.refresh (http://localhost:8000/vendor/ember/index.js:22616:35)
at EmberObject.extend._actions.queryParamsDidChange (http://localhost:8000/vendor/ember/index.js:22328:22)
at Object.triggerEvent (http://localhost:8000/vendor/ember/index.js:24563:38)
at trigger (http://localhost:8000/vendor/ember/index.js:44812:16)
at fireQueryParamDidChange (http://localhost:8000/vendor/ember/index.js:43612:9) index.js:14220
Uncaught Error: Assertion Failed: Error: You didn't provide enough string/numeric parameters to satisfy all of the dynamic segments for route article index.js:3658
This strange error only happens when I first clicked a Category so the queryParam category is changed, and then fire a transitionTo to an article.
I have tried to use the debugger; statement to get the source of the error. However it seems that is an event that calls this error. When searching the sourcecode I found that the error originates from line 44242 of ember.js.
Does anyone know why this error happen after I have transitioned to a non query-params-new route?
Edit: now in Github too: https://github.com/emberjs/ember.js/issues/5070 (comment on Github)
JSBin: http://emberjs.jsbin.com/yiquyupa
I ran into almost the same issue in an afterModel callback where the parent route/controller has queryParams.
I found that if you just pass the queryParams from the transition argument (not the queryParams argument which is null/undefined) into Route.transitionTo / Route.replaceWith then the transition completes.
Example:
afterModel: function(model, transition, queryParams) {
// FIXME: unresolved Ember issue https://github.com/emberjs/ember.js/issues/5070
this.replaceWith('another.route', model, { queryParams: transition.queryParams});
}
I don't know why this happens, but queryParams is still a relatively new feature and still has some rough edges.

Ember JS routing with multiple params

I am working on learning how to work with Ember JS and I have run into an issue.
I have been developing a very simple application that allows users to add/edit/delete books from a library and then search for books based on either the title or the author. Based on that I am attempting to create a link-to that would render like "/search/title/adventures_of_huckleberry_finn" which would tell the router to filter the model so that it only returns books with the title equals "Adventures of Huckleberry Finn" (I know I'll need to do some string formating for the character case and replacing spaces with underscores for the URL, but I'm not worried about that).
I have the following link-to in my template (the title is hard coded to simplify testing)
{{#link-to "books.search" "title" "adventures_of_huckleberry_finn"}}Search by title{{/link-to}}
I have the following route defined (I suspect I need to nest the second dynamic segment but I'm not sure how to do that since I don't want a new controller/route involved)
Books.Router.map(function () {
this.resource('books', { path: '/' }, function () {
this.route('search', { path: 'search/:search_by/:keyword' });
});
});
<!-- ... additional lines truncated for brevity ... -->
Books.BooksSearchRoute = Ember.Route.extend({
model: function (params) {
return this.store.filter('book', function (book) {
return book.get(params.search_by) == params.keyword;
})
},
renderTemplate: function (controller) {
this.render('books/index', { controller: controller });
}
});
Now if I hard code the value or either the :searchBy or :keyword parms in the BooksSearchRoute then this works fine, however when I attempt to dynamicly pass both params I get the following error:
More context objects were passed than there are dynamic segments for the route: books.search
How can I update the route so that it allows me to pass both dynamic params into the BooksSearchRoute correctly?
Here's the general concept, you essentially use a route as a dummy route used just for the composite key. Personally I'd still prefer joining the key with a dash or something and using a single route, but hey, here's how this would work.
App.Router.map(function() {
this.resource('colorWrap', {path:'/:pk1'}, function(){
this.resource('color', {path: '/:pk2'});
});
});
App.ColorWrapRoute = Ember.Route.extend({
model: function(params) {
return {pk1:params.pk1};
}
});
App.ColorRoute = Ember.Route.extend({
model: function(params) {
var wrapModel = this.modelFor('colorWrap');
return $.getJSON('/colors/' + wrapModel.pk1 + '/' + params.pk2);
}
});
{{link-to 'Click to see the red color!' 'color' 1 2}}
http://emberjs.jsbin.com/OxIDiVU/273/edit

How to use non id dynamic segments in ember router?

I have a question regarding non id based dynamic segments in the ember router.
I am using Ember.VERSION : 1.0.0-rc.1
I have a nested resource, and I need to use a url parameter in the path instead of an id.
but the ajax call to the json api needs to request an id.
So in my handlebars template I have:
{{#each thing in controller}}
{{#linkTo 'thing' thing.url}}{{thing.name}}{{/linkTo}}
{{/each}}
The things route looks like this:
App.ThingsRoute = Ember.Route.extend({
model: function() {
return App.Thing.find();
}
});
and the router:
App.Router.map(function() {
this.resource('things', function() {
this.resource('thing', {path:':thing_url'});
});
});
How do I map the url to resolve to the things id?
Fred is right. The model hook takes a params argument. Here is a more complete example.
App.ThingRoute = Ember.Route.extend({
model: function(params) {
return App.Thing.find(params.thing_url);
}
});
If you have already loaded all Things then you can use all method to retrieve all existing models and findProperty method to find array item by specific property:
App.ThingRoute = Ember.Route.extend({
model: function(params) {
return App.Thing.all().findProperty('url', params.thing_url);
}
});
Note that this will not work if required model is not loaded - the findProperty returns undefined if model is not in array and no request to server will be generated.
The model method has a parameter that gets passed in which would be thing.url in this case so you shold be able to access it there.
Read dynamic model part here
http://emberjs.com/guides/routing/specifying-a-routes-model/

From Ember Pre1 to Pre4: Multiple dynamic segments per route? Update: What is the allowed syntax for dynamic segments?

I am currently trying to migrate my Ember based on pre1 to the current release pre4. In my pre1-code, i defined a route as follows:
formCreated : Ember.Route.extend({
route : '/genre=:genre/sorting=:sorting/location=:location/range=:range/time=:date/:timeFrame',
....
})
This Route worked fine for me, but now i am struggling to mimic this behaviour with pre4. This is my approach:
App.Router.map(function() {
this.route("/");
this.route("formCreated", { path: "/genre=:genre/sorting=:sorting/location=:location/range=:range/time=:date/:timeFrame" });
});
App.FormCreatedRoute = Ember.Route.extend({
serialize: function(context, params){
// here i am returning a hash containing all the dynamic segments
}
});
What is going wrong?
When the App enters the state, the URL does not get updated properly. I am seeing this result:
/genre=:genre/sorting=:sorting/location=:location/range=:range/time=:date/6:00-19:00
So most of my dynamic segments do not get updated. I made sure that my custom serialize method is returning an appropriate hash object, where one property for each dynamic segment is set.
Are multiple dynamic segments per route still possible with pre4 or do i have to switch to some route nesting approach or something like that?
UPDATE: Root cause found:
I just discovered that the error happened because of the syntax i used for the route. I changed it to the following(replaced the "=" with "/"):
this.route("formCreated", { path: "/genre/:genre/sorting/:sorting/location/:location/range/:range/time/:date/:timeFrame" });
Is there any documentation on how the path may be structured? It seems that syntax has changed since ember-pre1. I would like to have a user friendly URL and those numerous Slashes make it difficult to read. Or is the rule, that a segment always has to start with ":/"?
You will need to use resource nesting, like described here and here
App.Router.map(function() {
this.route('/');
this.resource('genre', { path: '/genre/:genre_id' }, function(params) {
this.resource('sorting', { path: '/sorting/:sorting_id' }, function(params) {
...
});
});
});