how to append url with component's name in ember js - ember.js

I want to add the component's name to the URL in Ember js.
Example:
If the main URL is : localhost:4200/home ,
then in home,if I call/redirect to a component(say - abc), the URL should get appended:
localhost:4200/abc
or
localhost:4200/home/abc

If the main URL is : localhost:4200/home , then in home,if I
call/redirect to a component(say - abc), the URL should get appended:
How do you call/redirect to a component in ember?. If you got some hacky way to do that, then I will encourage you not to do this.
In Ember, the router matches the current URL to the routes that you've defined.
If you got /home/abc URL path, it means you have abc route nested inside home route.
Router.map(function() {
this.route('home', function() {
this.route('abc');
});
});
If you know all routes will come under home route, then you can define it manually. Suppose if you don't know or what will come , then go for defining the dynamic segments in URL.

You can do it by {{component}} helper.
You need to define dynamic path for home and send the component name from url to home controller by model hook.
Below are essential parts of the solution.
//router.js
this.route('home', {path: 'home/:cmp'});
//routes/home.js
model(params){
return params.cmp;
}
//templates/home.hbs
{{component model}}
Please take a look at this tiwddle

Related

How do you create nested dynamic routes with ember.js where child route replaces parent's template?

On Ember 3.15 (Octane)
I'm trying to create the following routes in my application
/cars
/cars/:car_id
/cars/:car_id/:model_id
The first two are fine and I've been able to create them using ember-cli
ember g route cars
ember g route cars/car
The problem with the third one is that I need the model template to be shown under the cars template, ie. replace the car template. So if I put an {{outlet}} on the car template, the model template is rendered in it fine but obviously with that {{outlet}} nothing happens when I navigate to /cars/5/2
My router looks like this
Router.map(function() {
this.route('cars', function(){
this.route('car', { path: ':car_id'}, function() {
this.route('model', { path: ':model_id' });
});
});
});
I've tried using an index route ember g route cars/car/index but the problem with this that the params are not available in the index route and can only be accessed on the car route.
As plan b I've created the car and model routes as top level routes (based on this answer), but I'd like to achieve the above because of a few reasons
it seems more logical ie, structuring the app based on the nesting of the routes
I have many nested routes and creating all of them as first level routes will become hard to maintain
ember doesn't apply the active class correctly with this configuration. For example if I have a navbar with Cars as an link, I'd want it to have the active styling on all three pages. But this doesn't work anymore because the second route will be called something like car and the third one something like model.
there are some issues with the urls that are created by default using <LinkTo />.
So if I have something like this in my car template
<ul>
{{#each #model.models as |model|}}
<li><LinkTo #route="model" #model={{model}}> {{model.title}} </LinkTo></li>
{{/each}}
</ul>
The actual link works properly in that it takes me to the correct model page, however, the url is shown as /cars/undefined/undefined. (Although this is fixable by passing #models={{array #model.id model.id}}, it seems like a workaround at this point)
The solution is indeed to use the index route.
So have cars.car.index and cars.car.model. However you should use the cars.car route to load the common car model. Then you can access it in the cars.car.index route with this.modelFor('cars.car').
Then you can access the params.car_id in the cars.car route, use it to load the car, and then access this car from the cars.car.index and cars.car.model routes with modelFor.

Override application.hbs template in Emberjs

In emberjs, I am in a situation that my application already has routes template that uses the application.hbs template, but now I want to create a new route templates that doesn't use application.hbs.
Is there any easy solution for that?
I have seen many answers but that doesn't match my specification and also my version of ember is 2.11.
Thank you.
Keep application.hbs as minimal and common across all routes as you can. What you shoud do is generate top level routes for your application.
Say you have a common setup where you have an authenticated section, post login, and a login section. It is common for pre and post login to have differing top level templates. Try something like this:
ember g route login
ember g route login/index
ember g route login/forgot-password
ember g route authenticated
ember g route authenticated/index
ember g route authenticated/profile
etc...
Your login.hbs would have its own style, and potentially child routes, which will assume that style and place subsequent nested templates in the {{outlet}} that others have mentioned.
File Structure:
routes/
-login/
----index.hbs
----forgot-password.hbs
-authenticated/
----index.hbs
----profile.hbs
login.hbs
authenticated.hbs
application.hbs
In the example above, login.hbs might look like this:
{{yellow-navbar}}
{{outlet}}
and authenticated.hbs like this:
{{pink-navbar}}
{{user.name}}
{{outlet}}
Now, the login/index.hbs and login/forgot-password.hbs templates will render in the login.hbs outlet. both of these pages will render a yellow navbar, and then their own content.
Because authenticated.hbs is another top level parent route, both authenticated/index.hbs and authenticated/profile.hbs will render their content beneath a pink navbar and a display of the current user's name.
if your application.hbs looked like this:
{{#general-site-container}}
<h2>Website Name</h2>
{{outlet}}
{{/general-site-container}}
Then all of the routes, both authenticated and login, will be in the general-site-container, and will all show the h2 with the website name.
An important note in this, and something that I see a lot of people get confused with, is that this folder structure does not dictate the actual path of the route.
The router might be configured like this, to avoid showing "authenticated" in the url:
Router.js
// login.index route assumed at root url /login
this.route('login', { path: '/login' }, function() {
// avail at /login/forgot-password
this.route('forgot-password', { path: '/forgot-password' }
});
//authenticated.index.hbs assumed at root avail at /
//notice that the authenticated parent route has a route of "/"
this.route('authenticated', { path: '/' }, function() {
// authenticated.profile route avail at /profile
this.route('profile', { path: '/profile' });
// as an exmaple you can further nest content to your desire
// if for instance your profile personal info section has a parent
// template/route
this.route('', { path: '/personal-info' }, function() {
this.route('address', { path: '/address' }); //profile/personal-info/address
});
});
i think you need to use {{outlet}} for achieve this.
create diffrent outlets where you need to show diffrent templates by overriding application template
{{outlet}} //application hbs default one
{{outlet "view1"}} // another template
{{outlet "view2"}} //another template
there should be view1.hbs and view2.hbs in order to render those templates

How show component only in a specific route?

I have a componente called hero (in application.hbs) and I wish display this componente only in home page.
I researched about how do this but without any success. Thanks!
After a few minutes and some searches on GitHub...
Just install ember install ember-truth-helpers and check the route name:
{{#if (eq currentRouteName 'index')}}
{{hero}}
{{/if}}
Glad to help!
I need more specifics, however, I am going to make the assumption that your home route is the '/' route.
The '/' route is actually your index route, so if you create an index.hbs file it will act as the template for your index route. And then your should just move the hero component to your index.hbs file.
I can't be sure your reasons, but I suspect that this could be a solution.
There is an invisible 'application' route... there is also an implicit 'index' route, but you can skip the confusion of that and just create a 'home' route and give it a path to the root. The application template will house the outlet - and then you can place your component just in the 'home' template;
(don't write an application route like this, but just for visualization)
Router.map(function() {
// overarching 'application' route
this.route('application', function() {
this.route('home', { path: '/' });
this.route('other');
});
});
Here is a twiddle with the full example in place. If this doesn't do what you want, then refer to the conditional suggestions. : )
Router.map(function() {
// here's an example of skipping of skipping the mysterious 'index' in another situation
this.route('books', function() {
this.route('books-list', { path: '/' });
this.route('book');
});
});
You can also render a component dynamically using component helper which save you a conditional statement inside your template.
The first parameter of the helper is the name of a component to render, as a string. So {{component 'blog-post'}} is just the same as using {{blog-post}}.
When the parameter passed to {{component}} evaluates to null or undefined, the helper renders nothing. When the parameter changes, the currently rendered component is destroyed and the new component is created and brought in.
So you can safely pass in anything to the component helper, in your case you can make the component name dynamically without worry an error will raised.
https://guides.emberjs.com/v2.1.0/components/defining-a-component/#toc_dynamically-rendering-a-component

In Ember.js, why is an error thrown if I set a route's path as {path: '/'}?

I have the router.js file of my project set up as follows:
Router.map(function() {
this.route('login');
this.route('projects', {path: '/'});
});
Whenever I visit the /login page, no content is displayed. Also, the following error appears in the console:
Error: There is no route named index
However, whenever I remove {path: '/'} from route, the login page works without issue.
Why is this happening? I've noticed that in other Ember projects like Ghost are able to achieve this just fine without any conflicts with a non-existent index route.
Note: I am using an ember-simple-auth mixin to redirect the visitor from / to /login.
I ran into the exact same problem when I tried to add the following route to my application:
this.route('user', { path: '/' });
I determined the problem was that in one of my templates I had a link like:
{{#link-to "index"}}Home{{/link-to}}
Since the root (index) path now belongs to the user route, there is no index rout. I needed to update my link to:
{{#link-to "user"}}Home{{/link-to}}
I suspect you might be referencing the index route, which no longer exists, somewhere in your templates or other code. Changing that to "projects" should work for you.

Ember router can transition to but not handle a url

Using Ember 2.1.0 with EmberData, I'm making a small blogging app. It has two routes
Router.map(function(){
this.route("posts", {path: "/"});
this.route("post", {path: '/:seo_friendly_link'});
}
The seo_friendly_link looks like this
/2015/10/28/my-blog-post-title/
In the index route, I display a list of posts with links to each post. If I click a link, the Ember app will transition to the post that I clicked on showing the seo-friendly-url in the browser. I emphasize transitionto-- the routing goes through that method in Ember router. Everything works fine up to here.
The problem:
However, if I drop/type that same url into the browser (rather than transition to it from a link on the homepage), I get an UnrecognizedURLError (before the model or even the beforeModel hook are called for the post). If I drop the url into the browser, the routing goes through the handleURL method on Ember Router, which doesn't happen if I click a link from the homepage. So my Ember app can transition to my seo_friendly_link, but not handle that url.
I'm not sure why.
Question: How can I create a route to recognize that link?
Code
There is a property on the Post model called
seo_friendly_link: DS.attr('string')
In /routes/post, I call the serialize method to create that parameter from the model property
serialize: function(model, params){
seo_friendly_link: model.get("seo_friendly_link");
}
Your dynamic segment /:seo_friendly_link doesn't match slashes, e.g. it will match /2015 but not /2015/10.
To match the whole path including slashes, change the : to an *:
Router.map(function(){
this.route("posts", {path: "/"});
this.route("post", {path: '/*seo_friendly_link'});
}