inline / inplace editing for different form inputs in Ember - ember.js

Views in the app we're developing are already written in Handlebars / Emblem and data is already taken from models.
I'm trying to figure out what's the best approach for inline / inplace in Ember. Problem: when nothing is clicked, the data is just a text. When you click the text depending on its type (date, plain text, list of items) the corresponding input field (date field, text field or select) is replaced and you can edit it.
Have you had experience with this issue? If so, please share your thoughts!

Here is one solution using an Ember.Component:
App.InlineEditComponent = Ember.Component.extend({
actions: {
toggleEditing: function() {
this.toggleProperty('isEditing');
}
}
});
With the template:
<script type="text/x-handlebars" id="components/inline-edit">
{{#if isEditing}}
<form {{action "toggleEditing" on="submit"}}>
{{yield}}
</form>
{{else}}
<span {{action "toggleEditing"}}>
{{value}}
</span>
{{/if}}
</script>
Usage:
<script type="text/x-handlebars" data-template-name="index">
{{#inline-edit value=someProperty}}
{{input value=someProperty type="date"}}
{{/inline-edit}}
</script>
Demo: http://emberjs.jsbin.com/OGEnOdA/2/edit
You can add more features (for example, end editing on focus-out the form element, etc.) but I think you get the basic idea.

Related

Ember action on a div with child anchor link

I have a div with a click action on it, and inside the div I have a normal anchor tag going to a link
example: http://emberjs.jsbin.com/wiledaduwi/edit?html,css,js,output
<div {{action "actionClick"}}>
google
</div>
Fortunately the action is firing, but the click on the anchor (and opening the link in a new tab) is not... Any suggestions?
Can you try:
<script type="text/x-handlebars" data-template-name="index">
<div>
<a href="http://www.google.com" target="_blank" {{action "actionClick"}}>google</a>
</div>
</script>
and in actions:
actions: {
actionClick: function() {
window.console.log('Action click!!!');
window.open('http://www.google.com');
}
}
As Kingpin2k suggested in his comment, what I was doing was generally considered bad form and not following ember's convention.
I've also confirmed this in the #needshelp Ember Slack chatroom.

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.

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.

Ember.js: Passing model into view

I have a controller with data about user accounts (icon, name, provider, etc.). Within the output of the each loop I have a view that will build a CSS class dynamically based on the provider passed in via that specific model.
<script type="text/x-handlebars" data-template-name="accountItem">
{{#each account in controller}}
{{#view App.AccountView}}
<h4>{{account.name}}</h3>
<img {{bindAttr src="account.icon"}} />
<i {{bindAttr class="account.provider"}}></i>
{{/view}}
{{/each}}
</script>
App.AccountView = Ember.View.extend({
tagName: 'a',
classNames: ['avatar-image'],
providerClass: function(el) {
// do something
}
});
The question I have is two-fold.
How do you pass in "account", or the currently iterated item, into the view?
After you pass it in, how do you reference it?
I'm sure this is something that happens quite often but I can't seem to find any examples. Can anyone offer some input on this please?
Views has a special content property in a view which allows a more simple approach: you just use a name of the model's property without the view.content. part.
Also, when you're iterating over controller, you can omit the name of loop variable and use this instead, like in this guide. This is not necessary but can make the code a bit cleaner.
Also, from within view's template you generally don't need to reference the outside variables although you can if you like..
{{#each controller}}
{{#view App.IndexView contentBinding="this"}}
<h4>{{name}}</h4>
<img {{bindAttr src="icon"}} />
<i {{bindAttr class="provider"}}></i>
<i> {{icon}} </i>
<i>{{provider}}</i>
{{/view}}
{{/each}}
And you can always access the content property from within the view with:
this.get('content');
The currently iterated item can be passed into the view with the help of property bindings and it can be refered as "{{view.property}}" in the template. For example:
{{#each account in controller}}
{{#view App.IndexView itemBinding="account"}}
<h4>{{view.item.name}}</h3>
<img {{bindAttr src="account.icon"}} />
<i {{bindAttr class="account.provider"}}></i>
<i> {{view.item.icon}} </i>
<i>{{view.item.provider}}</i>
{{/view}}
{{/each}}
I have created a simple jsfiddle for the above case. Do check it and let me know if you were able to resolve the issues.
Fiddle url : http://jsfiddle.net/nCyn6/3/

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