Edit a collection of Models with one controller - ember.js

I have a template that allows me to edit settings of a user. Within the usersettings my model is the actual user. And I have a 1-N Relationship between User-Settings:
{{#if isEditing}}
<button {{action 'doneEditing'}}>Done</button>
{{else}}
<button {{action 'edit'}}>Edit</button>
{{/if}}
<h1>Settings</h1>
{{#each this.setting}}
{{#if isEditing}}
{{name}}: {{view Ember.TextField valueBinding='value'}}
{{else}}
{{name}}: {{value}}
{{/if}}
{{/each}}
The problem is that if I click the Edit button, the "Edit" status is only coming to main controllere here. So my Buttons change, but within the loop, the Textfield is not appearing.
App.UserController = Ember.ObjectController.extend({
isEditing: false,
actions: {
edit: function(){
this.set('isEditing', true);
},
doneEditing: function(){
this.set('isEditing', false);
},
}
});
(I don't have a specific controller for the SettingItems in my Loop)
How do I handle such a case?

Yeah, you definitely can do it.
http://emberjs.jsbin.com/uwENUbeh/3/edit

Related

Material Design Lite: Dynamic Drawer Layout not showing with upgradeElement

application.hbs
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
{{navigation-bar class="mdl-layout__header"}}
{{#if Auth.authenticated}} //Auth is a service
{{navigation-drawer class="mdl-layout__drawer"}}
{{/if}}
<main class="mdl-layout__content">
<div class="page-content">
{{outlet}}
</div>
</main>
</div>
navigation-drawer.hbs
<span class="mdl-layout-title">Title</span>
<nav class="mdl-navigation">
{{#if Auth.authenticated}}
<span>Hi {{name}}</span>
<button type="button" name="logout">Logout</button>
{{else}}
{{#link-to 'login'}}Login{{/link-to}}
{{/if}}
</nav>
navigation-drawer.js
import Ember from 'ember';
/* globals componentHandler */
export default Ember.Component.extend({
Auth: Ember.inject.service('Auth'),
init() {
this._super(...arguments);
if(this.get('Auth').authenticated) {
this.set('name', 'lokesh');
}
},
didInsertElement () {
this._super(...arguments);
[].forEach.call(this.$(), function (el) {
componentHandler.upgradeElement(el);
});
}
});
navigation-bar.hbs
<div class="mdl-layout__header-row">
<span class="mdl-layout-title">Title</span>
<div class="mdl-layout-spacer"></div>
<nav class="mdl-navigation mdl-layout--large-screen-only">
{{#if Auth.authenticated}}
<button type="button" name="logout" {{action 'logout'}}>Logout</button>
{{else}}
{{#link-to 'login'}}Login{{/link-to}}
{{/if}}
</nav>
</div>
navigation-bar.js
import Ember from 'ember';
export default Ember.Component.extend({
Auth: Ember.inject.service('Auth'),
actions: {
logout() {
this.get('Auth').logout();
}
}
});
Login route
import Ember from 'ember';
export default Ember.Route.extend({
Auth: Ember.inject.service('Auth'),
actions: {
authenticate() {
this.get('Auth').login();
this.transitionTo('/');
}
}
});
<h3>Login Page</h3>
<button type="button" name="button"{{action 'authenticate'}} class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored">Login</button>
What i am trying to do?
I have a application route which has a navigation-bar displayed at all time and a navigation-drawer which should be displayed only if the user is logged in. so i wrote a {{#if Auth.authenticated}} condition to hide navigation-drawer. once user click login button in login route i am updating the AUTH service which is used across all the files. once user click login, he will routed to application route again. This time the condition {{#if Auth.authenticated}} will be true and navigation-drawer should show up. i checked in DOM. it has drawer. But the drawer button is not showing. When i refresh the page, it showed up. so i understood, material is acting on those components only during the onload time. However i understood that componentHandler.upgradeElement() is useful in case dynamic compoenents. i tried it in navigation-drawer.js. But it didn't work. Where i went wrong?
Just before upgradeElement, you may want to downgrade nodes under layout or immediate parent and them upgrade them. That way all the nodes get reset and load correctly. This worked for me.
componentHandler.downgradeElements(document.querySelector(".mdl-layout"));
componentHandler.upgradeDom();

Insert component in Controller action EmberJS

well i need to insert a component when the user click on button, my code:
dash.hbs
<button class="btn btn-primary" {{action 'solisXTax'}}> Consul</button>
dash.js //controller
actions:{ solisXTax(){ "theCode" }, }
and my componenet is ember-chart,
{{ember-chart type="Bar"
data=solsGraph
width=500 height=350
options=opcionesGrafica
legend=true}}
Thanks
I don't know if you are familiar with the handlebars conditionals, but you should read more about that in the guides
You can use a conditional like so:
//templates/application.hbs
<button class="btn btn-primary" {{action 'solisXTax'}}> Consul</button>
<hr/>
{{#if componentVisible}}
{{ember-chart}}
{{else}}
no component shown
{{/if}}
with the corresponding action in your controller
//controllers/application.js
export default Ember.Controller.extend({
componentVisible: false,
actions:{
solisXTax(){
this.toggleProperty('componentVisible')
}
}
});
Here is a twiddle that showcases using an if statement to toggle your component.
You could also dynamically toggle between different components, where one could be a empty component, but that might be overkill for your use case.

In Ember, how would one prevent an action that belongs to an encompassing element?

I'm using Ember, and I have a box that the user can click and it will pop open a modal window with more info.
I also have a button on that box that performs a different action.
If I click on the button, the correct action is triggered, but it also triggers the action for the encompassing <div>. How do I prevent that action on the <div>, while allowing the action from the <button>?
Here's my template:
<div {{action 'openModal' 'productResultOverview' this}} class="simpleproducttile">
<div class="row simpleproducttitle">
<p>{{ProductId}}<i class="icon-export helpiconleft"></i><img src="img/largebox.png"></img></p>
</div>
<div class="row simpleproductdescription">
<p>{{ProductDescription}}</p>
</div>
<div class="medium primary btn customizebutton">
<input type="submit" {{action "sendToSavedItems"}} value="Select and Customize"/>
</div>
</div>
Edit:
Action for the button:
App.ProductResultController = Ember.ObjectController.extend({
actions: {
sendToSavedItems: function() {
console.log('sending to saved items');
}
}
});
And the action openModal is contained within ApplicationRoute:
App.ApplicationRoute = Ember.Route.extend({
id: 'modal',
actions: {
openModal: function (modalName, model) {
console.log('opening modal', modalName, model);
return this.render(modalName, {
into: 'application',
outlet: 'modal',
model: model
});
},
//....
});
From the Ember.js docs:
By default, the {{action}} helper allows events it handles to bubble up to parent DOM nodes. If you want to stop propagation, you can disable propagation to the parent node.
What you should do is add bubbles=false to the inner items:
<input type="submit" {{action "sendToSavedItems" bubbles=false}} value="Select and Customize"/>
This should stop the click from propagating to the parent <div>.

how to add a new record UI in ember

Just when I think that I'm getting a handle on ember, this happens and I run into a brick wall.
I have
App.Router.map(function() {
this.resource('customers', function() {
this.resource('customer', {
path : ':customer_id'
});
customers route :
App.CustomersRoute = Ember.Route.extend({
model: function() {
return this.store.find('customer');
},
customer controller :
App.CustomerController = Em.ObjectController.extend({
needs: ['state'],
isEditing: false,
isNotEditing: Ember.computed.not('isEditing'),
actions : {
startEditing: function() {
this.set('isEditing',true);
this.set('validationErrors', '');
},
save: function() {
and these templates :
<script type="text/x-handlebars" data-template-name="customers">
...
{{outlet}}
...
</script>
<script type="text/x-handlebars" data-template-name="customer">
...
{{#if isEditing}}
<div class="well well-sm">
<a class="btn btn-success" {{action save}}>Save</a>
<a class="btn btn-warning" {{action cancel}}>Cancel</a>
</div>
{{else}}
<div class="well well-sm">
<a class="btn btn-primary" {{action startEditing}}>Edit</a>
<a class="btn btn-danger" {{action delete}}>Remove</a>
</div>
{{/if}}
this is all working well for me. I can select a customer, press the edit button, form inputs get enabled, press the save button and changed data is persistent back to the db
however : this is my brick wall.
How do I enable a feature to create a new record : I dont want to duplicate the edit form, just show blanks
I am assuming that I need to put "new" into the router map
this.resource('customers', function() {
this.resource('customer', {
path : ':customer_id'
});
route('new');
});
but do I create a CustomerNew controller and CustomerNew route and CustomerNew template ?
I have put an action into the customers controller
<a class="btn btn-primary btn-xs pull-right" {{action startNew}}>New</a>
do I really need to create a route & controller & template just to handle the new action ? Or can I reuse the customer/1 route/controller/template ?
thanks
To do things The Ember Way (TM) you'd want to use a new route, controller, and template. Ember does make it easy to consolidate your logic and not have to duplicate code. In templates you can do this with partial, and in your JS code you can do it with Ember.Mixin.
Here's a JSBin of the general idea : http://jsbin.com/ucanam/1056/edit
Here's the interesting parts of the templates :
<script type="text/x-handlebars" data-template-name="customers/new">
Add a new customer<br/>
{{partial "customers/form"}}
</script>
<script type="text/x-handlebars" data-template-name="customer/edit">
Edit a customer<br/>
{{partial "customers/form"}}
</script>
<script type="text/x-handlebars" data-template-name="customers/_form">
{{input value=name}}
<button {{action save}}>Save</button>
<button {{action cancel}}>Cancel</button>
</script>
And then the controllers :
App.CrudController = Ember.Mixin.create({
actions : {
save : function(){
this.get('model').save();
this.transitionToRoute('customers');
},
cancel : function(){
this.get('model').rollback();
this.transitionToRoute('customers');
}
}
});
App.CustomersNewController = Ember.ObjectController.extend(App.CrudController,{});
App.CustomerEditController = Ember.ObjectController.extend(App.CrudController,{});

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.