How can I click to edit on a text field with ArrayController? - ember.js

I was following the tutorial but the tutorial is for the object controller. In an Array controller how do I properly pass in the object for the text field so it triggers the update for that model object?
Right now I can double click, and then type in some value, and if I hit enter I get the value plus undefined method set.
Uncaught TypeError: Object asdasdasdasdasd has no method 'set'
I guess it's passing the raw value into the controller and then trying to run methods off of that. How do I get it to pass the actual model?
View:
<ul>
{{#each}}
<li {{bind-attr class="isEditing:editing"}} {{action "editWorkout" this on="doubleClick"}}>
{{#if isEditing}}
{{view Ember.TextField class='edit' action="updateWorkout"}}
{{else}}
{{#link-to 'workout' this}} {{title}} {{/link-to}}
{{/if}}
</li>
{{/each}}
<li>
{{newWorkoutName}}
</li>
</ul>
Controller:
EmberWorkouts.WorkoutsController = Ember.ArrayController.extend
actions:
editWorkout: (workout) ->
workout.set('isEditing', true)
createWorkout: ->
title = #get('newWorkoutName')
workout = #store.createRecord('workout', title: title)
#set('newWorkoutName', '')
workout.save()
updateWorkout: (workout) ->
workout.set('isEditing', false)
workout.save()
isEditing: false
Repo here if you want to investigate: https://github.com/ecl1pse/ember-workouts/tree/master/app

You can specify an itemController in your each and then use an ObjectController for each item in your list.
{{#each itemController="workout"}}
<li {{action editWorkout on="doubleClick"}}>
<!-- Other stuff goes here -->
</li>
{{/each}}
EmberWorkouts.WorkoutsController = Ember.ObjectController.extend({
editWorkout : function(){
this.set('isEditing', true);
}
});
Here's a JSBin of the general idea : http://jsbin.com/ucanam/1038/edit

Related

How do I pass a value from one .hbs file to another

I am trying to pass the index value from posts.hbs to the delete-post.hbs and then from delete-post.hbs to my delete-post.js function.
posts.hbs
<br>
<h2> Blog Posts </h2>
<ul>
{{#each model as |onePost index|}}
<li id = {{index}}>{{onePost.title}} {{delete-post}}
</li><br>
{{/each}}
</ul>
{{add-new-post}}
delete-post.hbs
<a class="ui red button" {{action 'deletePost' parentNode.id `}}>Delete</a>`
delete-post.js
import Component from '#ember/component';
export default Component.extend
({
actions:
{
deletePost(input)
{
alert(input);
}
}
});
You can pass the parameter by = operator like {{component-name componentProperty=outerProperty. In your case:
{{#each model as |onePost index|}}
<li id = {{index}}>{{onePost.title}} {{delete-post parentNodeId=index}}
</li><br>
{{/each}}
Also, you should change parentNode.id to parentNodeId in your delete-post.hbs

How to get current model for a route from a controller or a view?

I want to implement item-list/item-detail pattern in Ember, but the nuance is that the detail view must appear next to the selected item. E.g:
<ul>
<li><div>Post 1<div></li>
<li><div>Post 2<div></li>
<li><div>Post 3<div></li>
<li>
<div>Post 4<div>
<div>
<ul>
<li>Comment 1</li>
<li>Comment 2</li>
<li>Comment 3</li>
</ul>
</div>
</li>
<li><div>Post 5<div></li>
</ul>
The Handlebars template I tried is:
<script type='text/x-handlebars' data-template-name='posts'>
<ul>
{{#each model}}
{{#linkTo 'post' this}}
<div>{{title}}</div>
{{/linkTo}}
{{#if isSelected}} <!-- How to implement isSelected ? -->
<div>{{!-- render selected post's comments --}}</div>
{{/if}}
{{/each}}
</ul>
</script>
I tried this in controller:
App.PostController = Em.ObjectController.extend({
isSelected: function() {
return this.get('content.id') === /* what to put here? */;
}
});
What I'm stuck with is how to implement isSelected in 'Ember'-way? Am I going in right direction?
You are on the right track. The trick is to use a different controller to wrap products in the item-list vs. the item-detail. So start by specifying that the handlebars {{each}} helper should wrap each entry in a ListedProductController
{{#each model itemController="listedProduct"}}
Now define ListedProductController, adding the isSelected function you'd been writing. Now it can reference the singleton ProductController via the needs array, comparing the product that was set by the router to the listed product.
App.ProductController = Ember.ObjectController.extend({});
App.ListedProductController = Ember.ObjectController.extend({
needs: ['product'],
isSelected: function() {
return this.get('content.id') === this.get('controllers.product.id');
}.property('content.id', 'controllers.product.id')
});
I've posted a working example here: http://jsbin.com/odobat/2/edit

emberjs in the console I see that records are created but they are not displayed by handlebars

First many thanks to Mike Grassotti, for helping in the IRC. He helped resolved the bugs with the save method.
My problem is that in the console I see that records are created but they are not displayed.
I am using ember-data to create new record. The addComment function creates the record in a transaction, while the save function, only calls this.transaction.commit.
In the console after I click save(), the record seems created but handlebars doesn't display the newly created record. This is an excerpt of what I see in the console when I dig into the results of console.log
>committed: Object
firstRecordKind: "belongsTo"
firstRecordName: "post"
>firstRecordReference: Object
clientId: 4
id: "ember411"
>type: EmBlog.Comment
ClassMixin: Ember.Mixin
>FIXTURES: Array[1]
0: Object
body: "ty"
id: "ember411"
post: "1"
To create a new record, click on post -> then 'post title' -> at the bottom addComment- > then save and you will see that the record was not created.
The relevant bit of code from the jsfiddle. This controller will not have a route as it will be sideloaded
EmBlog.CommentNewController = Em.ObjectController.extend({
needs: ['postsShow'],
isAddingNew: false,
addComment: function(body){
console.log("this: ", this.toString());
var post = this.get('controllers.postsShow.content');
console.log(post);
transaction = this.get('store').transaction();
console.log(transaction);
console.log(this.get('content').toString());
this.set('content', transaction.createRecord(EmBlog.Comment, ({post: post })));
this.transaction = transaction;
console.log(this.get('content').toString());
this.set('isAddingNew', true);
},
save: function(){
var comment = this.get('content');
comment.one('didCreate', this, function() {
this.set('isAddingNew', false);
});
this.transaction.commit();
}
});
The relevant bit from the handlebars template
<script type="text/x-handlebars" data-template-name="posts/show">
<h1>Post</h1>
<h3> {{title}} </h3>
<h3> {{body}} </h3>
<br/>
<p> {{#linkTo 'posts.index'}} back {{/linkTo}}</p>
<p> {{#linkTo 'posts.edit' content}} Edit the post {{/linkTo}}</p>
<br/>
<b> Comments</b>
{{render 'comment/new' comments}}
</script>
<script type='text/x-handlebars' data-template-name='comment/new'>
{{#if controller.isAddingNew}}
<form {{action save on='submit'}}>
{{view Ember.TextArea valueBinding="body" placeholder="body"}}
<button type="submit"> save comment </button>
</form>
{{/if}}
<br/>
<div>
<button {{action addComment}} {{bindAttr disabled="isAddingNew"}}>Add Comment</button>
</div>
</script>
Thanks
hmm, maybe i'm blind, but i can't see any code for displaying comments in your templates.
something like
<ul>
{{#each comment in comments}}
<li>{{comment.body}}</li>
{{/each}}
</ul>
should probably do the trick.

How to render hasMany associations each with their own controller

So my models are set up like this :
App.Post = DS.Model.extend
comments: DS.hasMany 'App.Comment'
App.Comment = DS.Model.extend
post: DS.belongsTo 'App.Post'
I'm trying to create a view that has all posts and all comments display, but I need to decorate the comment objects.
This is what I'd like to do but, to no avail :
<ul>
{{#each post in controller}}
<li>{{post.title}}</li>
<ol>
{{#each comment in post.comments itemController="comment"}}
<li>{{comment.body}}</li>
{{/each}}
</ol>
{{/each}}
</ul>
Properties defined in a App.CommentController are simply not found by the template.
I suspect that Ember.OrderedSet does not implement the itemController param - is there a workaround for this?
You need to use the new expiremental control tag. This will load the view and controller for the specified type:
<ul>
{{#each post in controller}}
<li>{{post.title}}</li>
<ol>
{{#each comment in post.comments}}
{{ control "comment" comment }}
{{/each}}
</ol>
{{/each}}
</ul>
You will need to enable this expiremental feature first. Put this before ember is loaded:
<script type='application/javascript'>
ENV = {
EXPERIMENTAL_CONTROL_HELPER: true
};
</script>
Also, you will need to specify that the controller for comments should not be a singleton, otherwise there will only be one controller instantiated for all comment views:
// this is needed to use control handlebars template properly per
// https://github.com/emberjs/ember.js/issues/1990
App.register('controller:comment', App.CommentController, {singleton: false });

Ember.js binding array element to view

I have the following code in a ember.js template. userController is an ArrayController, with multipe "users" within.
{{#each CollaborativeEditor.userController}}
{{#view CollaborativeEditor.OnlineUserView userBinding="this"}}
<div class="avatar">
<div class="avatar_name">{{name}}</div>
<div class="avatar_status">{{status}}</div>
</div>
<div id="dropdown-1">
<ul>
<li><a href="#" {{action startChat target="onlineUser"}}>Talk to </a></li>
</ul>
</div>
{{/view}}
{{/each}}
This is the code of the respective view:
CollaborativeEditor.OnlineUserView = Ember.View.extend({
tagName: 'li',
startChat : function() {
console.log(this.get('user'));
}
});
Although, the name and status is set correctly for each user, the startChat action attached to the link always prints the first user of the array to the console.
What is wrong with the binding ?
Thanks a lot for your request, to put it in a jsfiddle !
While I was trying to reproduce the error there, I realized the problem, and it has nothing to do with ember.
The div with id="dropdown-1" was called from another link and it was always the same id, therefore always the same action with its user-binding.
Now I've bound the Id to the user-object and it works perfectly.