Ember - Adding an extra action for #link-to - ember.js

I have a simple Ember application where I have a dynamically generated list of links-to. On a single click per link, I show some detail about the clicked item.
I also want to add "ondblclick" event to the link-to. Is this at all possible? If not, I'm not attached to having link-to for single and double clicks.
I want to be able to keep the functionality I already have for the single-click event, and also add a double-click event (ideally, without firing a single-click event meanwhile ). I want to be able to store the double clicked titles and ids associated with them.
I tried using Ember.View object for this (commented out below), and I tried adding {{action "collectDoubleClicked" on="doubleClick"}} into the link-to, but that doesn't work. No luck so far.
Any help will be much appreciated.
Here is my HTML:
<script type="text/x-handlebars" data-template-name="application">
<div id="headerDiv">
<ul>
<li>
<image src="logo.png" style="width:439px;height:102px;"/>
</li>
<li>
{{#link-to 'home'}}Home{{/link-to}} | {{#link-to 'help'}}Help{{/link-to}}
</li>
</ul>
</div>
<div class="collections">
{{partial 'collections'}}
</div>
<div class="statistics">
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" id="collections">
<div id='collectionsDiv'>
{{#each}}
{{#link-to 'item' this }} <!-- {{action "collectToSearch" on="doubleClick"}} -->
{{title}}
{{/link-to}}
{{/each}}
</div>
</script>
And my JavaScript:
App = Ember.Application.create();
App.Router.map(function () {
this.resource('home', {
path: '/'
});
this.resource('help');
this.resource('item', {
path: ':item_id'
});
});
App.ApplicationRoute = Ember.Route.extend({
model: function () {
return items;
}
});
var items = [{
id: 1,
title: 'Item 1',
contentType: 'Image',
description: 'description 1'
}, {
id: 2,
title: 'Item 2',
contentType: 'Text',
description: 'description 2'
}, {
id: 3,
title: 'Item 3',
contentType: 'Undefined',
description: 'description 3'
}];
App.ApplicationController = Ember.ArrayController.extend({
actions: {
collectDoubleClicked
function () {
console.log("collectToSearch: ", this.get('model.title'));
}
}
});
/**
App.Application = Ember.View.extend({
itemTitles: [items.length],
itemIds: [items.length],
itemCountDoubleClick: 0,
doubleClick: function (title, id) {
console.log("double click");
itemTitles[itemCountDoubleClick] = title;
itemIds[itemCountDoubleClick] = id;
itemCountDoubleClick++;
return false;
}
});
**/

You can try something like this:
{{#link-to 'item' this }}
<span {{action "doubleClickAction" on="doubleClick"}}>
{{title}}
</span>
{{/link-to}}
If my understand is true, span catch event before link.
But I think, we have more true way

I don't think there's a way to handle doubleClick without triggering singleClick. Have a look at this jsBin. Before doubleClick is even triggered, click was already triggered twice. I understand what you're trying to do and it makes sense.

Related

Ember.js: How to filter a model by route

I'm trying to adopt the completed/archived-route-behavior from this TodoMVC-Tutorial.
I'm using Ember 1.7.0, Ember Data 1.0.0-beta.9 and Handlebars 1.3.0.
I want to get all active users on my index route (example.com/organization/users) and all archived users on my archived route (example.com/organization/users/archived).
But the filter doesn't work: archived users are shown on my index route and vice versa, but my console.log output is correct.
Update: Please check this JSBin: http://emberjs.jsbin.com/puxeludeviga/3/
That's how I tried it:
Docket.OrganizationUsersRoute = Docket.AuthenticatedRoute.extend({
model: function() {
return this.store.find('user');
},
renderTemplate: function() {
// render all posts
this.render('organization/users', {
into: 'application'
});
// render toolbar
this.render('organization/toolbar', {
into: 'application',
outlet: 'toolbar'
});
}
});
Docket.OrganizationUsersIndexRoute = Docket.OrganizationUsersRoute.extend({
model: function() {
console.log('index');
return this.store.filter('user', function(user) {
return !user.get('archived');
});
}
});
Docket.OrganizationUsersArchivedRoute = Docket.OrganizationUsersRoute.extend({
model: function() {
console.log('archived');
return this.store.filter('user', function(user) {
return user.get('archived');
});
}
});
And that's my template:
<ul class="entries">
{{#each}}
<li>
<div class="actions">
<button {{action "remove" this}} class="ei-icon-close"></button>
</div>
<div class="link" {{action "edit" this}} data-uk-modal="{target:'#user-modal'}">
<span class="before">{{initial}}</span>{{name}}
</div>
</li>
{{else}}
<li>No users</li>
{{/each}}
</ul>
My (shortened) router.js file:
Docket.Router.map(function() {
// organization route
this.resource('organization', function() {
// user routes
this.resource('organization.users', { path: '/users' }, function() {
this.route('archived');
});
});
});
I think I found your issue. The thing here is that template you're rendering the users into, has this name:
organization/users
and turns out that it matches to you organization.users route, so, it is always rendering the data from that route. You need to change the name of you template, let's say to:
organization/users_list
and then, use that in your routes, it will not have any problems because the name is different to the users route.
something like:
<script type="text/x-handlebars" data-template-name="organization/users_list">
<div class="top">
<h1>Users</h1>
{{#link-to 'organization.users.index' class="button-archive"}}active{{/link-to}} - {{#link-to 'organization.users.archived' class="button-archive"}}archived{{/link-to}}
</div>
<ul class="entries">
{{#each}}
<li>{{name}} - Archived: {{archived}}</li>
{{else}}
<li>No users to show</li>
{{/each}}
</ul>
</script>
and in your routes:
renderTemplate: function() {
// render all posts
this.render('organization/users_list', {
into: 'application'
});
// render toolbar
this.render('organization/toolbar', {
into: 'application',
outlet: 'toolbar'
});
}

Ember - partial template with fixture data

I just started with Ember and have a basic web app structure in place. I have a partial template set up and want to bring some test data into it. I can see my test data if I use my 'home' template for it, but I can not get it into my collections partial template. I'm almost certain it has to be related to basic Ember concepts that I have no familiarity with. Here is my simplified html and below is the Ember js. If anybody has any idea how I could bring the 'each' loop from 'home' template into my partial 'collections' template, I'll be very thankful:
[code]
<script type="text/x-handlebars" ><!-- data-template-name="application" -->
<div id="main">
<ul>
<li>
<image src="logo.png" style="width:439px;height:102px;"/>
</li>
<li>{{#link-to 'home'}}Home{{/link-to}} | {{#link-to 'help'}}Help{{/link-to}}</li>
</ul>
</div>
<div class="collections">
{{partial 'collections'}}
</div>
<div class="statistics">
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" id="collections">
COLLECTIONS<br/>
<!-- here is where I wand the 'each' loop to go -->
</script>
<script type="text/x-handlebars" id="home">
OnLoad : This is Home Page<br/>
<ul>
{{#each}}
<li>
<label>{{title}}</label>
</li>
{{/each}}
</ul>
</script>
<script type="text/x-handlebars" id="help">
Welcome to Help Page
</script>
[/code]
And here is JS code for the above:
[code]
App = Ember.Application.create();
App.Router.map(function(){
this.resource('home', { path: '/' });
this.resource('help');
});
App.CollectionsRoute = Ember.Route.extend({
model: function(){
return items;
}
});
App.HomeRoute = Ember.Route.extend({
model: function(){
return items;
}
});
var items = [
{
id: 1,
title: 'Item 1',
belongsTo: 'parent path 1'
},{
id: 2,
title: 'Item 2',
belongsTo: 'parent path 2'
},{
id: 3,
title: 'Item 3',
belongsTo: 'parent path 3'
}
];
[/code]
partial 'collections' have the same context of application template. So if you declare:
App.ApplicationRoute = Ember.Route.extend({
model: function(){
return items;
}
});
Will be able to use:
<script type="text/x-handlebars" id="collections">
COLLECTIONS<br/>
<ul>
{{#each}}
<li>
<label>{{title}}</label>
</li>
{{/each}}
</ul>
</script>

Ember.js Router: Embedded resources

I'm creating an Ember application to display twitter feeds but I am having trouble with displaying individual tweets through embedded resources.
The code is as follows:
Templates
<script type="text/x-handlebars" data-template-name="tweets">
<div id="stream">
{{#each tweet in controller}}
<div class="tweet">
<p class="tweet_text">{{tweet.text}}</p>
<p> {{#linkTo "tweet" tweet}} {{tweet.id}} {{/linkTo}}</p>
</div>
{{/each}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="tweet">
<div id="detail">
{{text}}
</div>
</script>
Router
window.App = Ember.Application.create({
LOG_TRANSITIONS: true
});
App.Router.map(function(){
this.resource('tweets',function(){
this.resource('tweet',{path: ':tweet_id'})
});
});
// (1) App.Router.map(function(){
// this.resource('tweets')
// this.resource('tweet',{path: ':tweet_id'})
// });
App.IndexRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('tweets');
}
});
App.TweetsRoute = Ember.Route.extend({
model: function(){
var me = [];
$.getJSON("http://search.twitter.com/search.json?q=emberjs&rpp=200&count=200&callback=?",
{},
function (data) {
$.each(data.results,function(k,tweet){
var tweet = App.Tweet.create({
created_at: tweet.created_at,
from_user: tweet.from_user,
profile_image_url: tweet.profile_image_url,
text: tweet.text,
id: tweet.id
});
me.pushObject( tweet );
});
});
return me;
}
});
Objects & Controllers
App.TweetsController = Ember.ArrayController.extend({});
App.Tweet = Ember.Object.extend({
created_at: "",
from_user: "",
profile_image_url: "",
text: "",
id: 0
})
As you can see, I have a commented our router (1) which works in finding the correct tweet, and rendering it in the tweet template. However, I would like this route to be nested so that I can implement it as a Master-Detail application.
Using the LOG_TRANSITIONS, I can see that the correct routes are initialised, but I cannot get the nested resource path to render.
Any ideas would be hugely appreciated, thanks in advance.
I got this working. For anyone stuck on something similar, this is how I did it:
Templates - Changed the {{#linkTo}} "tweet"... to {{#linkTo}} "tweets.tweet"... AND added an {{outlet}}
<script type="text/x-handlebars" data-template-name="tweets">
<div id="stream">
{{#each tweet in controller}}
<div class="tweet">
<p class="tweet_text">{{tweet.text}}</p>
<p> {{#linkTo "tweets.tweet" tweet}} {{tweet.id}} {{/linkTo}}</p>
</div>
{{/each}}
</div>
{{ outlet }}
</script>
Router - Changed 'this.resource' to 'this.route'
App.Router.map(function(){
this.resource('tweets',function(){
this.route('tweet',{path: ':tweet_id'})
});
});
Caveat
I think this is a workaround and that the nested resource was the correct approach in this context. I understand that a nested route should be "a verb" or action route. I would still be grateful if anyone knows the correct approach to the question but hope the above helps others where relevant.

Emberjs bindAttr inside of #each

Code for view is
Ember.View.extend({
template: Ember.Handlebars.compile(html), // html is in string
content: function() {
return [
{ Title: "Dashboard", ID: "dashboard" },
{ Title: "Invoices", ID: "invoices" },
{ Title: "Expenses", ID: "expenses" },
{ Title: "People", ID: "people" },
{ Title: "Reports", ID: "reports" },
{ Title: "Settings", ID: "settings" }
]},
iconClass: function(link){
return "icon icon-" + link.ID
}
});
Template (show above as "html") looks like this:
<ul>
{{#each link in view.content}}
<li>
<a>
<span class="icon" {{bindAttr class="view.iconClass(link)"}}></span>
<span class="title">{{link.Title}}</span>
</a>
</li>
{{/each}}
</ul>
This renders
<span class="icon" data-bindattr-2="2"></span>
So additional class attribute is not rendered. Am I doing something wrong with scope or?
NOTE:
I changed my code to show what I want to do.
EDIT
According to the new question, you'll have to use an Ember.CollectionView:
App.FooCollectionView = Ember.CollectionView.extend({
itemViewClass: Ember.View.extend({
iconClass: function() {
return "icon-dashboard icon " + this.get('content.ID');
}.property('content.ID')
})
});
As you can see, each itemViewClass has a property iconClass which depends on its content.id.
Now you'll have to add the collection view in the template of the view FooView:
<ul>
{{#collection App.FooCollectionView contentBinding="view.content"}}
<li>
<a>
<span {{bindAttr class="view.iconClass"}}>foo</span>
<span class="title">{{view.content.Title}}</span>
</a>
</li>
{{/collection}}
</ul>
Here we are using the {{collection}} Handlebars helper, and we bind the content of the FooView to the FooCollectionView.
It will automatically create an itemViewClass instance for each object in the CollectionView.content, set the its to the associated object, and add it to the view.
I suggest you to read the Ember.CollectionView documentation.
And you could try this solution in this JSFiddle.
For others who are having the problem with bindAttr resulting in something like:
data-bindattr-1="1"
make sure you are using
{{bindAttr src="myvariable"}}
instead of {{bindAttr src="{{myvariable}}"}}
Might save you some time searching for the answer, this was what caused my code not to work.
Another simple way to do this is to add a computed property to your model. In the example below I needed a specialized style atribute.
Model ----
App.Photo = Em.Object.extend(
objectId: null
url: ""
style: (->
"background-image:url('" + #get("url") + "')"
).property("url")
)
Template -----
{{#each item in App.photoController}}
<div {{bindAttr style="item.style"}}></div>
{{/each}}

Recursive view in handlebars template not working after upgrading to Ember 0.9.6

I used to be able to do something like this to get a nested unordered list of items:
Javascript:
App.Menu = Em.View.extend({
controller: App.menuController.create({}),
tagName: 'ul',
templateName: 'Menu',
pageBinding: 'controller.page'
});
Handlebars:
<li>
{{page.menuTitle}}
{{#each page.childrenPages}}
{{view App.Menu pageBinding="this"}}
{{/each}}
</li>
index.html:
<script type="text/x-handlebars">
{{view App.Menu}}
</script>
Now after updating to the latest Ember.js (0.9.6), only the last item of any given collection of items is being displayed (as a single <li> within the <ul>). In previous versions of Ember, a nested <ul>/<li> list with all items of a given collection was displayed.
I think that instead of a new App.Menu view being created each time through {{#each}}, the existing view is just being reused... any ideas on how I can achieve something similar to the old behavior?
I think the issue is that by creating the controller inside the class App.Menu the controller property is the same for every concrete instance of App.Menu, see Understanding Ember.Object.
I've moved the binding to the specific controller out of the view class and it works, see http://jsfiddle.net/pangratz666/DgG9P/
Handlebars:
<script type="text/x-handlebars" data-template-name="Menu" >
<li>
{{page.menuTitle}}
{{#each page.childrenPages}}
{{view App.Menu pageBinding="this"}}
{{/each}}
</li>
</script>
<script type="text/x-handlebars">
{{view App.Menu pageBinding="App.mainPage" }}
</script>
JavaScript:
App = Ember.Application.create({});
App.Menu = Em.View.extend({
tagName: 'ul',
templateName: 'Menu'
});
App.mainPage = Ember.Object.create({
menuTitle: 'main page',
childrenPages: [Ember.Object.create({
menuTitle: 'subtitle 1',
childrenPages: [Ember.Object.create({
menuTitle: 'subtitle 1 - child 1'
})]
}), Ember.Object.create({
menuTitle: 'subtitle 2',
childrenPages: [Ember.Object.create({
menuTitle: 'subtitle 2 - child 1'
})]
})]
});​