My Goal: emulate nested route, but render it into application outlet.
For example:
/videos - top route
/videos/video001 - nested route
/videos/video001/slide001 - not nested. It is on the same level as /videos.
How I am doing this:
I have following router:
App.Router.map(function () {
this.resource('videos', { path: '/videos' }, function () {
this.resource('video', { path: '/:video_id' });
});
this.resource('slide', { path: '/videos/:video_id/:slide_id' });
});
To make 'slide' route work as expected I am overriding 'serialize' method, and
return 'video_id' and 'slide_id'
And at this point everything seems to be ok. At least page loads as expected.
What is the issue?
When I navigate to "/videos/video001" from "/videos/video001/slide001" via "link-to' helper,
I see following error: "Error while processing route: video".
And nothing more. I can't understand what kind of error happens and
why ember can't process route correctly. However I see that URL has been changed to "/videos/video001".
Any suggestions?
How to debug this situation or at least get any useful error message?
UPDATE
This article describe exact current situation and gives some solutions: http://hashrocket.com/blog/posts/ember-routing-the-when-and-why-of-nesting
Ok. I wasn't able to figure out what is the issue, and seems to be nobody able to help with that even on ember irc channel. So I have found interesting article http://hashrocket.com/blog/posts/ember-routing-the-when-and-why-of-nesting and implemented nesting via {into: 'application'}, but to make it work correctly i have overrided renderTemplate hook in all templates to define correct rendering order.
And everything works fine.
I do something similar but without the multiple IDs. Try this in your router:
this.resource('videos', { path: '/videos' }, function () {
this.resource('video', { path: '/:video_id' });
this.resource('videos.video.slide', { path: '/videos/:video_id/:slide_id' });
});
Your routes should be App.VideosRoute, App.VideosVideoRoute, and App.VideosVideoSlideRoute. Same for the controllers (if needed)
Related
To link to record you can use something like this in your route:
this.route('clients', function() {
this.route('all',function(){
this.route('view',{
path:'view/:client_id'
});
});
});
So if the user were to go to:
/clients/all/view/-KdFmDwwWAHDFjjaG6aA
They could view that client record.
Is it possible to link at a deeper level? For example:
/clients/all/view/-KdFmDwwWAHDFjjaG6aA/property/-KdFeTqqUIKLFqbaP9aB
?
That way you could be looking at a specific client record and then launch an overlay for example to show the specifics on a single property that client has for sale?
I'm not sure how to structure the router or the link-to to accomplish this?
I hope I understand your question correctly. Here is my answer,
Yes, it's possible to have a deeper level, I will change your route config a bit to :
this.route('clients', { path: '/clients' }, function(){
this.route('view', { path: '/:clients_id' }, function(){
this.route('property', { path: '/property/:property_id' });
});
});
So in this case, your link-to code in the HBS would be
{{#link-to 'clients.view.property' clientId}}
whatever
{{/link-to}}
and now file structure is :
clients/
|___index.hbs
|___view.hbs
|___view/
|___propery.hbs
Please remember that you need to also modify your route.js for each properly. I assumed you don't have any problems for that.
if you need more help please let me know.
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 have a route that catches all missing routes and renders a 404-style page. I would like to create a route that matches any url starts with "/browse/" such as "/browse/shoes/red". This seems like the correct way to do that:
App.Router.map(function() {
this.route('browse', { path: '/browse/*fields' });
this.route('missing', { path: '/*badPath' });
});
However, ember's RouteRecognizer always picks the missing route over the browse route. (The logic that does this is in sortSolutions of route-recognizer.js .) Is this a bug in Ember? Is there a right way to use glob routes and still have a 404 handler?
By the way, I can create a resource for browse instead of making it a route like this:
App.Router.map(function() {
this.resource('browse', { path: '/browse' }, function() {
this.route('baz', {path: '/*'});
});
this.route('missing', { path: '*' });
});
This still has the same problem.
I think this must be a bug...
Here's a JSBin : http://jsbin.com/ucanam/1403/edit
Here you can see it going directly to the 'missing' route as expected:
http://jsbin.com/ucanam/1403#/some/random/stuff
And a failed attempt at going directly to a 'browse' route :
http://jsbin.com/ucanam/1403#/browse/test/stuff
I'm a newbie to Ember Data and all I've done to date is FIXTURE data but today I'm trying to graduate to the real deal and am realising that I don't know enough about how to connect the model and the API's call signature.
Specifically I'd like to be able to call an endpoint GET /activities/[:user_id]/[date]. This would load an array of "Activity" objects but only those for a given date. I know that I can offset the API's directory with:
DS.RESTAdapter.reopen({
namespace: 'api'
});
In my case the api prefix is appropriate. I think I should also be able to get the date component solved by setting up a route something like this:
this.resource('activities', { path: '/activities' }, function() {
this.route('by_date', {path: '/:target_date'});
});
The above is just an educated guess because I'm completely at a loss on how to get the user_id component into the URL signature. Can anyone help? Are there any good tutorials or examples of basic Ember Data use cases?
Also, because I know I'm going to run into this next ... how does one add parameters to the url string (aka, GET /foobar?something=value) versus parameters to the URL itself (like above)?
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
UPDATE
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
I've implemented the suggestions from #intuitivepixel but am still having some problems ...
First off I tried to hard code the values for userId and dateBy:
Router:
this.resource('activities', { path: '/activities' }, function() {
this.route('by_date', {path: '/:user_id/:by_date'});
});
Route:
App.ActivitiesByDateRoute = Ember.Route.extend({
serialize: function(activity) {
return {
userId: 1,
dateBy: "2013-07-01"
};
}
});
Sadly that did not work. I think I understand why -- although I don't have a quick way to fix this -- but more disturbing for me was that when I manually put in the parameters into the URL: http://restful.service.com/api/activities/1/2013-07-01. The results are quite surprising to me:
Initially the debugging messages suggest a success:
This however, is not correct as no network requests are actually made
If you reload the browser, it will now go out and get the Activities but to my surprise it also goes out to find the specified user. Hmmm. That's ok, the user 1 is pulled back successfully.
The Activity, however, is just a GET /activities call which fails because this endpoint needs the user and date qualifier to work. Why weren't these included in the request?
I know that I can offset the API's directory with:
You can also set a different URL of our API if it's the case:
DS.RESTAdapter.reopen({
url: 'http://myapihost.com',
namespace: 'api'
});
This would produce a URL like http://myapihost.com/api/
The above is just an educated guess because I'm completely at a loss on how to get the user_id component into the URL signature.
Following your example and adding the user_id dynamic segment, let's say you have this router map definition:
this.resource('activities', { path: '/activities' }, function() {
this.route('byDate', {path: '/:user_id/:target_date'});
});
and this is your {{linkTo}} helper:
{{#each activity in model}}
{{#linkTo 'activities.byDate' activity}}
{{/each}}
then to build your url out of multiple dynamic segments you could hook into your route's serialize function and returning a hash composed out of the dynamic segments your URL needs:
App.ActivitiesByDateRoute = Ember.Route.extend({
serialize: function(activity) {
return {
user_id: activity.get('userId'),
target_date: activity.get('targetDate')
}
}
});
The code above will generate a URL like /activities/[userId]/[targetDate] when the {{linkTo}} link is clicked. The example assumes that the properties you need to build your URL are available in your Activity model.
Also, because I know I'm going to run into this next ... how does one add parameters to the url string (aka, GET /foobar?something=value) versus parameters to the URL itself (like above)?
This kind of URL queries are not yet supported by the ember framework, but the are good workarounds/projects that try to deal with that missing feature like: https://github.com/alexspeller/ember-query, and if this PR get's merged some day then you will have them also soon in ember, but for the time beeing you could use the above mentioned library to have support for custom queries. For the current status whether the lib get's merged or not have look here: http://discuss.emberjs.com/t/query-string-support-in-ember-router there is a discussion going on.
Hope it helps.
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) {
...
});
});
});