Passing parameter for link-to in Emberjs - ember.js

for some reason i need to pass my route one extra parameter with linkTo and use this parameter in my Route i try to find a way and find some source but its not enough my suggestion is like this :
{{#link-to 'someRoute' parameter1}}
{{#link-to 'someRoute' parameter2}}
App.SomeRoute = Ember.Route.extend({
//using parameter
});
is it possible to use transitionTo and pass parameter when changing?

You can use multiple parameters with the link to helper.
{{#link-to 'someNestedRoute' model1 model2}}Deep Route{{/link-to}}
You also can use transitionTo from a route (or transitionToRoute from controller) and send in multiple models as well.
transitionTo('someNestedRoute', model1, model2);

Related

Multiple layouts in Ember 2

I need implement next application structure with 3 routes:
localhost/users
localhost/posts
localhost/settings
'users' and 'posts' routes should have basic layout1 with main navbar.
'settings' route should have another layout2 with second navbar.
How can I implement multiple layouts approach with Ember > 2.12?
Can I set a layout name/path for each route or group of routes?
I can think of two possible recommended approaches to this problem. I've used both in different scenarios. You can either:
Use a component to encapsulate each navbar and then present them accordingly in each template
Set the templateName attribute of each route to use the correct template.
The component approach seems to be the easiest/most used in my experience. It also allows you to have differences within your base route template. e.g.:
users.hbs:
{{layout1}}
<h1>Users<h1>
...
posts.hbs:
{{layout1}}
<h1>Posts</h1>
...
While if you use the templateName approach, you are locked into using the same exact template. So, if you need any customization between any page that uses the same layout, you must use a subroute. e.g.:
routes/users.js:
import Ember from 'ember';
export default Ember.Route.extend({
templateName: 'layout1'
});
routes/posts.js:
import Ember from 'ember';
export default Ember.Route.extend({
templateName: 'layout1'
});
templates/layout1.hbs:
<nav>...</nav>
{{outlet}}
A third possible approach, though I don't necessarily recommend it, is to dynamically replace the navbars in the application.hbs template. The application controller/template have access to a special attribute called currentPath, which you can used to create two computed properties (isLayout1 and isLayout2).
With that, this becomes a viable, though like I said, not necessarily recommended solution:
application.hbs:
{{#if isLayout1}}
<nav>layout 1</nav>
{{else}}
<nav>layout 2</nav>
{{/if}}
{{outlet}}

How to make route parameters optional in Ember.js?

In Ember.js, given these routes:
this.route('chefs', { path: ":country/chefs"});
this.route('recipes', { path: ":country/recipes"});
I am required to put the positional params in the link-to component, like:
{{#link-to 'chefs' 'mx'}}Mexico Chefs{{/link-to}}
How can I avoid specifying some params in all my link-to components?
I'm thinking the 'chefs' route could use a default parameter coming from a service. But how? Any other ideas?
Here is a Twiddle:
https://ember-twiddle.com/fe34f195723fffa88869558e94f3fabc
Edit
Another example for this need is when using nested routes. Imagine a menu component with links to "chefs" and "recipes". When placed inside a parent route named 'country', say "/ca", the links don't need params.
{{#link-to 'chefs'}}Chefs{{/link-to}}
{{#link-to 'recipes'}}Recipes{{/link-to}}
These will navigate between '/ca/chefs' and '/ca/recipes'. But when this hypothetical menu is put on a root-level route, say '/login', the menu will error out "Assertion Failed: You attempted to define a {{link-to "chefs"}} but did not pass the parameters required for generating its dynamic segments..."
I would like to give the route a default "country" parameter when one is not passed by the link.
One alternative I see, which doesn't seem too elegant, is to create a service and inject the "country" param in every link.

Passing an object as query-params parameter in link-to

Using the Route.transitionTo function, I can call,
this.transitionTo('posts', {queryParams: {sort: 'title'}});
So, say I have an object,
qpms={sort:'title'}
Now, I can make it,
this.transitionTo('posts',{queryParams:qpms});
I also know that, in the template,
{{#link-to 'posts' (query-params qpms)}}text{{/link-to}}
instead of,
{{#link-to 'posts' (query-params sort="title")}}text{{/link-to}}
won't work.Is there some way to achieve the same effect as provided by the Route.transitionTo function, in the link-to helper??
So that in the posts controller, I can still get it as,
queryParams: ['sort'],
sort: null,
??
No you couldn't.
With current implementation of query-params helper you couldn't achieve it.
But you can create your own helper to work for.
Please take a look at this twiddle
If i understand you correct, you can use passing params to a like on Template
{{#link-to 'posts' qpms}}text{{/link-to}}
Also you be sure that qpms must be define in Controller , Route or Component. like bellow
// Component
export default Ember.Component.extend({
qpms: {sort: 'title'},
})
// Controller
export default Ember.Controller.extend({
qpms: {sort: 'title'},
})
OR
http://site/#/url/params/SORT
export default Ember.Route.extend({
model(params){
return params;
}
});
Note:: that above code it not necessary, Ember automatically return url params

In Ember can the render helper get its model from the route instead of from its parameter?

On a template you can use the {{render 'route' model}} helper to embed a template and controller into another template, but this will set the model passed as an argument as the model. Is there a way to embed a route into a template but have the model come from the ebeded route's model hook? The reason why I can't use the parameter method is that the route's model is an RSVP hash and it depends on a dynamic segment.
If you need a template backed by the route, you shouldn't try to embed it somehow, just define new nested route in your router, create a tempalte and put {{outlet}} instead of {{render}}. It will do absolutely the same - resolve the route, fetch the model, setup controller and render given template.
If you still need to embed async data via {{render}} helper in some reason, you can use conditionals:
{{#if model.length}}
{{render 'template' model}}
{{/if}}

How can I set a link to route with a dynamic segment

How can I set a link to route with a dynamic segment. According to guide I start with this
window.App = Ember.Application.create()
App.Router.map ->
#resource 'products'
#resource 'product', path: '/product/:product_id'
in my template:
{{#linkTo "product.1"}}products{{/linkTo}}
Unfortunately this gives me the follwing error:
Uncaught Error: assertion failed: The attempt to linkTo route 'product.1' failed.
The router did not find 'product.1' in its possible routes: 'products', 'product', 'index'
{{linkTo}} expects the route defined in the Router.map, so in according to your mapping it should be simply product.
As for the dynamic segment, you also have to pass an object which will be serialized in the ProductRoute. The serialization in almost all scenarios occur without the developer having to do anything since Ember relies on conventions. In rare cases, one must implement serialize a little differently, but for most cases you don't have to touch it.
If you're using {{linkTo}} inside an {{each}} loop you can do it like this:
{{#each product in controller}}
{{#linkTo product product}}Details{{/linkTo}}
{{/each}}
or
{{#each controller}}
{{#linkTo product this}}Details{{/linkTo}}
{{/each}}
Where the first argument is the route name and the second is your model object. In the first code the object has been also named as product, while in the second it's simply being passed as this, which is the product of the iteration.
If you have an unusual scenario where you have to link to a dynamic route while not using the {{each}} loop, you have to expose the object in the controller (preferred) or view. Then you'd have to do something similar to the following:
App.SomeController = Em.Controller.extend
product: null
App.SomeRoute = Em.Route.extend
###
controller is actually `SomeController` here
model is not being used, and is null, while the actual model being
supplied to the controller is `product`, retrieved from store
###
setupController: (controller, model) ->
product = App.Product.find 1
controller.set 'product', product
return
While your template would be similar to this:
{{#linkTo product controller.product}}Product{{/linkTo}}
How does the route know the id?
Conventions. The route will serialize the object you pass, and expose an object with a single property, which has the name of the model for that route, followed be "_id", which in this case would be product_id, so when you click that link, the app activates the ProductRoute, runs the serialize method creating that id property, which will subsequently be used as the argument of the model hook. That's where you call find passing params.product_id as argument. Then the model returns a promise of that model which will be used by the setupController, exposing the object to the view layer as controller.content or simply controller.