emberjs : add active css class to link based on current route - ember.js

I am using Ember version 1.8 . Does anyone know how to automatically highlight menu link when user is in that route. Plese help. I saw few Stack overflow posts on doing it. but they looks old and is not working for me
I have the following menu in handlebars template
<ul class="nav navbar-nav">
<li>
{{#link-to 'posts'}}Posts{{/link-to}}
</li>
<li>
{{#link-to 'comments'}}Comments{{/link-to}}
</li>
</ul>
router.js looks like
this.resource('post', { path: 'posts/:post_id'},function(){
this.resource('comments', { path: '/comments' });
});

Ember automatically adds a class of active to a routed currently being visited. You can define what that should look like in css, for example:
.active {
background: yellow;
}
The rest just works...
See a working demo here

Related

Display dynamic content in Ember application template

I am creating an Ember app that manages a list projects and tasks for each project. In the app's navigation, I want to display the name of the selected project. If someone navigates to /projects/1/tasks, I want the page to display project 1's title, along with links to pages specific to that project. Here is what I have started for my application.hbs file of how I expected it to work, however the project title is blank and the links don't work:
<nav id="nav-menu">
<ul>
<li class='menu-project-title'>
{{#link-to 'projects'}}{{project.title}}{{/link-to}}
</li>
<li class='menu-separator'> </li>
<li>{{#link-to 'projects.tasks' project}}Tasks{{/link-to}}</li>
<li>{{#link-to 'projects.people' project}}People{{/link-to}}</li>
</ul>
</nav>
<div class="container" id='main-outlet'>
{{outlet}}
</div>
If I know every route will always have a project returned, what is the best way to pass that data into the application template?
You could use an Ember.computed.readOnly property in your application controller.
App.ApplicationController = Ember.Controller.extend({
needs: ['project'],
activeProject: Ember.computed.readOnly('controllers.project.model')
...
});
But maybe this isn't the best solution. As far as I understand it, the project route/template is always used? So why not move everything to that template.

ember.js: conditional positioning of nested resource outlet

starting from the bloggr-client of the ember guide i would like to include the outlet of 'post' inside the 'posts' each loop, resulting in some kind of accordeon-like behaviour.
e.g., the router looks like this:
App.Router.map(function() {
this.resource('posts', function() {
this.resource('post', { path: ':post_id' });
});
});
the template (cleared of html tags for legibility) should do something like:
<script type="text/x-handlebars" id="posts">
{{#each model}}
{{#link-to 'post' this}}{{title}}{{/link-to}}
{{#if :post_id given and corresponding with this post}} <-- that's pseudo code ;-)
{{outlet}}
{{/if}}
{{/each}}
</script>
any idea how to accomplish this properly?
UPDATE 1:
to clarify, output on url '/posts' should be:
post 1 title
post 2 title
post 3 title
on url '/posts/1':
post 1 title
complete post 1
post 2 title
post 3 title
on url '/posts/2':
post 1 title
post 2 title
complete post 2
post 3 title
Basically, you want to be able to displays all of the posts on the posts route as an accordion? You're going about it wrong because you can only have one {{outlet}} per template. What you want to do is build a component, which would look something like this:
<script type="text/x-handlebars id="components/post-card">
{{#link-to 'post' post tagName="h2"}}{{post.title}}{{/link-to}}
<p>{{post.snippet}}</p>
</script>
And call it in the posts route like this:
<script type="text/x-handlebars" id="posts">
<ul>
{{#each}} -> if you're iterating through the model, no need to specify
<li>
<h3 {{action makeActive}}>{{title}}</h3>
{{#if active}}
{{post-card post=this}}
{{/if}}
</li>
{{/each}}
</ul>
</script>
You would add active as a property in your model, and makeActive would be an action in your controller that would make active true for the given model, and make the other ones false. This would model an accordion, though your route would not update.

Nested route in resource not being accesible by Link-To

I can't make it work. The problem lies in the projects route, notes and info routes are not being linked
App.Router.map(function() {
this.resource('about');
this.resource('projects', function() {
this.route('new');
this.resource('project', { path: ':project_id'}, function(){
this.route('info', { path: "/info"});
this.route('notes', { path: "/notes"});
});
});
this.resource('posts', function() {
this.route('new');
this.resource('post', { path: ':post_id' });
});
});
The project template making the call to project_notes.hbs and project_info.hbs is as follows.
<div class="navbar navbar-inverse">
<div class="navbar-inner">
<a class="brand" href="#">{{title}}</a>
<ul class="nav">
<li>{{#link-to 'project.Info' project}}Info{{/link-to}}</li>
<li>{{#link-to 'project.Notes' project}}Notes{{/link-to}}</li>
</ul>
</div>
</div>
{{outlet}}
After reading this I was able to go a step further but still it's not working. Let me know if you need more info like the project model or anything.
Error
This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid.
Thanks in advance.
EDIT
The route is ProjectInfoRoute which is fine, the pointing URL is /projects/:project_id/info which is also absolutely fine. But when I click in the Project in order to go to Project/Project_id now it says There is no route named info.index
This is defining info as a this.route if I use this.resource it's like the route for info gets twisted since it's InfoRoute instead of ProjectInfoRoute. (If I go for the resource, after getting into the project template, I click on info and I can't get to see that template.) I'm scratching my head here.
Don't send it, additionally it should be link-to should be lower case
<ul class="nav">
{{#if model}}
<li>{{#link-to 'project.info' model}}Info{{/link-to}}</li>
<li>{{#link-to 'project.notes' model}}Notes{{/link-to}}</li>
{{else}}
do some other menu here, go to projects, or something
{{/if}}
</ul>
additionally you can find out the scope and values of properties really easy by tossing them into the template or logging them
{{project}}
{{log project}}
{{log model}}
{{log this}}

Ember.js {{linkTo}} to itself does not render

I have a problem with a linkTo that points to itself. The actual problem is in an application that has a sidebar with a set of links. The first time a click the link the model and view is loaded and displayed properly. However on the second click the view and/or model disappear.
I've condensed the problem in this jsfiddle. The index route displays a list of links and when clicking on one of the links it will display the detail. In the detail page I have a link to itself but when I click it the model does not show.
The detail template shows the content fine but note the {{firstName}} or {{lastName}}
<script type="text/x-handlebars" data-template-name="item">
<h2>Item Content:</h2>
{{#linkTo "item" id}}Reload me{{/linkTo}}
{{content}}
<ul>
<li>{{firstName}} {{lastName}}</li>
</ul>
</script>
I think the issue is similar to Ember.js - linkTo error on second call
Updated sample
Here is a new example With linkTo at the top levelwhere the {{linkTo}} item is in the top level application template
<script type="text/x-handlebars" data-template-name="application">
{{#linkTo "test" 0}}Test 0{{/linkTo}}
{{outlet}}
</script>
Following #intuitivepixel solution using an action gives me the same result
<script type="text/x-handlebars" data-template-name="application">
<a href="#" {{action reloadMe "test" 0}}>Test 0</a>
{{outlet}}
</script>
Not everything can be done with the {{linkTo}} helper, IMO for this kind of feature (like a reload) you should go for a {{action}} helper instead.
First define the action that does the routing for you when called:
App.TestRoute = Ember.Route.extend({
events: {
reloadMe: function(route, content) {
this.transitionTo(route, content);
}
},
serialize: function(model) {
return {id: model.id};
}
});
And then in your template:
<a href="#" {{action reloadMe "test" content}}>Reload me</a>
See here how you could implement it: http://jsfiddle.net/FSd6H/4/
Hope it helps.

Change Navbar based on login state

I’ve been trying, using Rails/Ember pre-4, to do a fairly typical thing, that is have a page with a navbar and a content section. The navbar only changes on login (shows logout button when logged in and login and register buttons when logged out), not on every page change.
At first thought i could do something in the application.hbs template such as:
{{view navbar}}
{{outlet}}
where i set up navbar to respond to login state changes (managed by a state manager). This didn’t seem to work.
Then i tried something like (also in application.hbs):
{{outlet navbar}}
{{outlet}}
and tried setting navbar in each route, which results in lots of duplication and also didn’t ultimately work.
Before posting code, wanted to know if anyone already has a good solution to this common situation where certain parts of your page such as a navbar or sidebar only change upon some change in app state, not on every page change.
There are lots of ways to get this done. The first approach you described is closest to what we are doing. In past ember versions we used view helper for this, today we use {{render}} but it's the same basic concept. For example, application.hbs might look like this:
{{render navbar}} {{outlet}}
Now navbar.hbs can use a simple {{#if}} helper to swap links based on login state.
<div class="navbar">
<div class="navbar-inner">
{{#linkTo index class="brand"}}My App{{/linkTo}}
<ul class="nav">
<li>{{#linkTo index}}Home{{/linkTo}}</li>
<li>{{#linkTo about}}About{{/linkTo}}</a></li>
</ul>
<ul class="nav pull-right">
{{#if isAuthenticated}}
<li><a {{action logout}} href="#">Logout</a></li>
{{else}}
<li><a {{action login}} href="#">Login</a></li>
{{/if}}
</ul>
</div>
</div>
Now we add logic to NavbarController that tracks and manages login state.
App.NavbarController = Ember.ArrayController.extend({
isAuthenticated: false,
login: function() {
this.set('isAuthenticated', true);
},
logout: function() {
this.set('isAuthenticated', false);
}
});
In a real app NavbarController would proxy these requests to another controller, perhaps currentUserController. I've created a working sample here: http://jsbin.com/iyijaf/6/edit