Transitioning from one view/template to another in Ember.js rc1 - ember.js

In the "new" Ember.js (post Feb 15 2013), the old routes and transitions no longer work. I'm trying to figure out how to replace them. I've created a super-simple jdfiddle to illustrate what I currently have.
{{#each item in controller}}
<li><a {{action editDetails item}}> {{item.title}} </a></li>
{{/each}}
Each item has an ID, and this is successfully passed to editDetails() on the IndexController (click on one of the three hard-coded items in the output):
App.IndexController = Ember.ArrayController.extend({
editDetails: function(params){
console.log('details! ' + params.id);
}
});
Another template is waiting for a controller to show it and hand it the item for the details.... but nothing I have tried from this point works. So, how do I get these two hooked up together?

I updated your jsfiddle.
{{action}} helper are no longer used to transitioning between routes.
Now you must use the {{#linkTo}} helper.
{{#each item in controller}}
<li>{{#linkTo 'editDetails' item}}{{item.title}}{{/linkTo}}</li>
{{/each}}
Please take a look to the emberjs guides

Related

ember: manipulate the DOM (like hide a long list of items)

I'm new to ember. I have a demo app working, and I'm moving towards making it look nice.
One issue I'm starting to grapple with is how to manipulate DOM elements. Coming from a server-side world, it's been pretty easy to just throw some jquery at stuff like this. Doesn't appear to be as straightforward in ember. But I'm probably missing something or approaching it wrong.
The immediate problem is: I have a list of 40-some <li> elements and I want to create a toggle to show/hide the list after the first 10 items.
I got something to work in my component like this:
import Ember from 'ember';
let $ = Ember.$;
export default Ember.Component.extend({
didInsertElement() {
this._super(...arguments);
Ember.run.scheduleOnce('afterRender', this, this.afterRenderEvent);
},
afterRenderEvent() {
let listTotal = $("#myList li").length;
$("#myList li").slice(10, listTotal).hide();
}
});
The problem is that when actions trigger and the view is re-rendered, afterRenderEvent() doesn't get called again, and the list shows in its entirety.
The above component corresponds to this template:
<ul id="myList">
{{#each aggs.categories as |category|}}
<li><a href="#" {{action (action add "filter_breadcrumb" category.key)}}>{{category.key}} ({{category.doc_count}})</a></li>
{{/each}}
</ul>
Is there a way to get around this? OR, is there a more "ember" way to approach this problem (and DOM manipulation in general)?
Introduce showCount property in controller and have action to set showCount to total list count.
import Ember from 'ember';
export default Ember.Component.extend({
showCount: 10,
actions: {
setShowCount(count) {
//you can set total count
this.set('showCount', count);
}
}
});
Install ember truth helpers addon or write computed property to check.
<ul id="myList">
{{#each aggs.categories as |category index|}}
<li style="{{if (gt index showCount) 'display:none'}}"><a href="#" {{action (action add "filter_breadcrumb" category.key)}}>{{category.key}} ({{category.doc_count}})</a></li>
{{/each}}
</ul>
If you don't want to display then you can just iterate just showCount aggs.categories alone by writing computed property or using ember-composable-helpers junk method
<ul id="myList">
{{#each (chunk showCount aggs.categories) as |category index|}}
<li><a href="#" {{action (action add "filter_breadcrumb" category.key)}}>{{category.key}} ({{category.doc_count}})</a></li>
{{/each}}
</ul>

How to set specific view in emberJS with itemcontroller

I have the following code:
{{#each categories.items itemController="item"}}
When I open the Ember inspector, it shows the view to be "virtual". I want to set the view to be "item" so that it follows the ember view I set out called itemView. I know we can set an itemController: is it possible to set an item view?
Yes it is possible using the optional 'itemViewClass' parameter.
{{#each categories.items itemController="item" itemViewClass="otherView"}}
Though I would recommend discontinuing using that and itemController as the latest Best Practice is to use a component within the each block.
So for your example:
// Ember 1.10+
{{#each categories.items as |item|}}
{{some-component item=item}}
{{/each}}
// Ember 1.9-
{{#each item in categories.items}}
{{some-component item=item}}
{{/each}}
Then you put your logic needed in the component object instead of the item controller.

Ember action on itemController not working

Here are my controllers:
App.DesignPhotosController = Ember.ArrayController.extend({
itemController: 'designPhoto'
});
App.DesignPhotoController = Ember.ObjectController.extend({
needs: ['designPhotos'],
toDelete: false,
actions: {
toggleDelete: function() {
this.set('toDelete', !this.get('toDelete'));
}
}
});
And my template:
{{#each}}
<ul>
<li>
{{title}}
{{#if toDelete}}
<button class="restore" {{action "toggleDelete"}}>Restore</button>
{{else}}
<button class="delete" {{action "toggleDelete"}}>Delete</button>
{{/if}}
</li>
</ul>
{{/each}}
However, when I click on the "Delete" button, I get a message logged:
Error: Nothing handled the action 'toggleDelete'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble.
As far as I can tell I am doing this correctly, bit I tried forcing it by various combinations of:
Adding target=this to the action
Adding {{#each item in controller}} and target=item
Changing the action to {{action toggleDelete this}}, with and without quotes
Nothing works.
Can anyone point out what I am doing wrong?
One possible reason of this behaviour is a bug present in 1.13 (up until the very last 1.x release, 1.13.13), which breaks actions that should be processed by item controllers.
In case you can't revert to release 1.12, the second workaround from the question
changing {{#each}} to {{#each item in controller}} and adding target=item to the action
is the officially recommended one and has worked for my code, although the first one
adding target=this to the action (with simple {{#each}})
should probably work too.
(I suspect that OP left either of these in the code and didn't register that it fixed the issue, because both came up as false negatives earlier due to Firefox's very persistent caching.)

link-to action parameters are not working in ember js

Hi i am very new to ember js. i pass action parameters(id ) on link-to action in template but i did not get the values in my controller.
My Template code as follows:
index.html:
<script type="text/x-handlebars" data-template-name="search">
{{#each model.results}}
// here i pass id value along with action
{{#link-to 'profile' id action="profileinfo"}}
</script>
app.js:
App.SearchController = Ember.ObjectController.extend({
id: '',
actions:{
profileinfo: function(id){
// Here i access id value like this
console.log(id);
var id = this.get('id');})
when i click on the link action goes to Searchcontroller, but i get id value is empty.I follow some solutions in stack overflow but unfortunately i did not get anything. Please provide some solution
I don't get why you're using the {{#link-to}} helper for triggering an action on your controller. Maybe you could simply use the {{action}} helper ?
If you try doing it that way, would it work ?
<button type="button" {{action "profileinfo" id}}>Click me !</button>
From there, your console.log(id); should get your value.
EDIT
Would also work for a <a> tag
<a href="#" {{action "profileinfo" id}}>Click me !</a>
I've created popular addon for doing just that:
{{#link-to 'profile' id invokeAction='profileinfo'}}
Simply install it:
ember installember-link-action
Please leave a star if you enjoy it or leave feedback if you feel anything is missing. :) It works with Ember 1.13 and 2.X (tested on Travis CI).

Assigning 'active' class to selected list item in EmberJS

I have a list and I'd like to set one item as class="active" automatically. Given the following bootstrap code:
<ul class="nav">
<li {{bindAttr class="atIndex:active"}}>{{#linkTo "index"}}Index{{/linkTo}}</li>
<li {{bindAttr class="atAbout:active"}}>{{#linkTo "about"}}About{{/linkTo}}</li>
<li {{bindAttr class="atLogin:active"}}>{{#linkTo "login"}}Login{{/linkTo}}</li>
</ul>
atIndex, atAbout and atLogin reside in my ApplicationController.
To render as:
<ul class="nav">
<li class="active"><a...>Index{{/linkTo}}</li>
<li><a...>About<a></li>
<li><a...>Login<a></li>
</ul>
What's the best way to do this with Ember 1.0 pre4? I'd rather not add special code to every view or controller.
PS - atIndex: true works, but atIndex: function() {return true; }.property().volatile() does not. Which makes me think I'm doing something wrong.
Thank you!
{{#link-to "dashboard" tagName="li" href=false}}
<a {{bind-attr href="view.href"}}>
Dashboard
</a>
{{/link-to}}
By far the cleanest way to solve this is by taking advantage of the linkTo helper's built-in support for setting the active class when rendering links. AFAIK this is not yet documented other than in the source code:
implementation: https://github.com/emberjs/ember.js/blob/master/packages/ember-routing/lib/helpers/link_to.js#L46
example: https://github.com/emberjs/ember.js/blob/master/packages/ember/tests/helpers/link_to_test.js#L120
To take advantage of this feature just adjust your css to style based on having an active class on the link instead of the li element. If you really need to style the li you can create a custom view and helper that extends Ember.LinkView and uses an li but changing css will be far easier.
--- UPDATE ----
Since we all love twitter bootstrap just changing the css is perhaps not such a great option. In that case, the following will do the trick:
App.ApplicationView = Ember.View.extend({
currentPathDidChange: function() {
Ember.run.next( this, function() {
this.$("ul.nav li:has(>a.active)").addClass('active');
this.$("ul.nav li:not(:has(>a.active))").removeClass('active');
});
}.observes('controller.currentPath')
});
Working example using ember linkTo helper with bootstrap pills: http://jsbin.com/ekobod/5/edit (requires ember-1.0.0-pre.4)
the active route's path is updated automatically in the ApplicationController via currentPath so I did something like that in my App...
In ApplicationController added properties like so:
isProductsActive: function(){
if ( this.get('currentPath') === 'products' ) return 'active';
else return '';
}.property('currentPath')
and in my ApplicationView template:
<li {{bindAttr class="isProductsActive"}}>
{{#linkTo "products"}}Products{{/linkTo}}
</li>
I made an ember-cli addon that handles this:
https://github.com/alexspeller/ember-cli-active-link-wrapper
EDIT:
Finally, the best way I've found to use the activate class of bootstrap li element using ember.js of the link.
{{#linkTo "dives" tagName="li"}}
<a {{bindAttr href="view.href"}}>Dives</a>
{{/linkTo}}
--------------8<--------------
DEPRECATED:
I guess the previous answers were relevant before Ember.js introduced the activeClass attribute for linkTo helper.
Now I would solve the problem like this :
<ul class="nav">
<li >{{#linkTo "index" activeClass="active"}}Index{{/linkTo}}</li>
<li >{{#linkTo "about" activeClass="active}}About{{/linkTo}}</li>
<li >{{#linkTo "login" activeClass="active}}Login{{/linkTo}}</li>
</ul>
Enber will automatically add the class when relevant.
If I may suggest another solution that requires nothing but Handlebars:
<li {{bind-attr class="view.innerLink.active:active"}}>
{{#link-to "path" viewName="innerLink"}}Click{{/link-to}}
</li>
This sets the LinkView object as a member of the parent view, which's active attribute you can then reference.
I found a pretty simple Solution using linked items in a list group(http://getbootstrap.com/components/#list-group-linked).
<div class="list-group">
{{#each thing in list}}
{{#link-to "details" thing.id tagName="a" href="view.href" class="list-group-item" {{thing.name}} {{/link-to}}
{{/each}}
</div>
Works with Bootstrap v3.1.1 and Ember v1.7.0
Just nest the {{link-to}} with a tagName on the outer one. I'm doing this on EmberJS 2.0.
{{#link-to "admin.websocket" tagName="li"}}
{{#link-to "admin.websocket"}}WebSocket{{/link-to}}
{{/link-to}}
If you want to use Bootstrap navigation in Ember then you can use Bootstrap for Ember that has out of the box support for this:
Github: https://github.com/ember-addons/bootstrap-for-ember
Demo: http://ember-addons.github.io/bootstrap-for-ember/dist/#/show_components/tabs
A lot of these answers are outdated. Here is a much cleaner (and DRY) version for Bootstrap and Ember 2.x:
{{#link-to "index" tagName="li" as |link|}}
Index Page
{{/link-to}}
I solved a similar problem by creating a view for each item and using classNameBindings (I have to say that i don't have a HTML list, i.e.<a>...</a> in my app, just list of <div>).
Here is the way it works for me:
In tasklist.handlebars i iterate over my custom view
{{#each tasks}}
{{view App.TaskListItemView contentBinding="this"....}}
{{/each}}
Ember will insert a view (i. e. <div>) for each item.
The view class for each item is defined in task_list_item_view.js as
App.TaskListItemView = Ember.View.extend({
controller: null,
classNameBindings: ['isSelected', 'isClosed'],
isClosed: function() {
var content = this.get('content');
return content && !content.isOpen(new Date);
}.property('controller.content.#each'),
isSelected: function() {
return (this.get('controller').isSelectedTask(this.get('content')));
}.property('controller.taskSelection.#each'),
....
});
Finally the template for the view just renders my link in tasklistitem.handlebars
<a {{action "selectTask" view.content target="view"}} rel="tooltip"
{{bindAttr title="view.content.comment"}} class="taskListLink">
....
</a>
AFAIK you have to specify the source data in the property() call to let ember know when to (re-) evaluate the property.
Hope that helps
I went with:
Ember.LinkView.reopen({
didInsertElement:function(){
if(this.$().hasClass('active')){
this.$().parent().addClass('active');
}
}
});
I didn't want to use the accepted answer as I wanted to keep my li elements as plain old html. There might be a better way to check the active state but I couldn't get access to the right property.