Sharing Data Between Models in Ember - ember.js

I've looked through stack overflow but not found any satisfying answers. Here's my problem.
I have a very simple app that I'm creating using EmberJS just for practice. It's an expense tracking application and basically has 3 sections : 'Friends', 'Expenses' and 'Summary' as shown in the screenshot.
The 'Friends' and 'Expenses' sections are working as they should. They allow me to browse through friends that are stored and enter new ones as well. Same goes with the expenses tab.
But I'm not able to get the summary page to work. I've included the code below for each of the controllers (ie friendsController, expensesController). Please do let me know how I can access information from the expenses model and display it in the summary tab. Thanks a million!
App.FriendsController = Ember.Controller.extend({
isEditing: false,
actions: {
add_friend: function() {
this.set('isEditing',true);
},
cancel: function() {
this.set('isEditing',false);
},
addFriend: function(){
var name = this.get('name');
var scrName = this.get('screenName');
var description = this.get('description');
var newFriend = this.store.createRecord('friend', {
name: name,
screenName: scrName,
description: description
});
this.set('name','');
this.set('screenName','');
this.set('description','');
newFriend.save();
this.set('isEditing',false);
},
}
});
App.ExpensesController = Ember.Controller.extend({
isEditing: false,
actions: {
add_expense: function() {
this.set('isEditing', true);
},
cancel: function() {
this.set('isEditing',false);
},
addExpense: function(){
var date = this.get('date');
var description = this.get('description');
var whoPaid = this.get('whoPaid');
var amount = this.get('amount');
var forWhom = this.get('forWhom');
if(!date.trim()) { return; }
if(!description.trim()) { return; }
if(!whoPaid.trim()) { return; }
if(!amount.trim()) { return; }
if(!forWhom.trim()) { return; }
var newExpense = this.store.createRecord('expense', {
date: date,
description: description,
whoPaid: whoPaid,
amount: amount,
forWhom: forWhom
});
this.set('date','');
this.set('description','');
this.set('whoPaid','');
this.set('amount','');
this.set('forWhom','');
newExpense.save();
}
}
});
Application Template :
<script type="text/x-handlebars">
<div class="container content-wrapper">
<div class="row">
<div class="col-md-12">
<h2>{{#linkTo 'index'}}Expense Tracker{{/linkTo}}</h2>
</div>
<hr>
<div class="nav well col-md-12 master">
<ul>
<li>{{#linkTo 'friends'}}Friends{{/linkTo}}</li>
<li>{{#linkTo 'expenses'}}Expenses{{/linkTo}}</li>
<li>{{#linkTo 'summary'}}Summary{{/linkTo}}</li>
</ul>
</div>
<div class="well col-md-12 detail">
{{outlet}}
</div>
</div>
</div>
</script>
Friends Template :
<script type="text/x-handlebars" id="friends">
{{#if isEditing}}
{{partial newFriend}}
<p>
<button {{action 'cancel'}} class="btn btn-success">Cancel</button>
<button {{action 'addFriend'}} class="btn btn-info">Save</button>
</p>
{{else}}
<p><button {{action 'add_friend'}} class="btn btn-primary">(+) New Friend </button></p>
{{/if}}
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Name</th>
<th>Screen Name</th>
<th>Description</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{{#each model}}
<tr>
<td>{{name}}</td>
<td>{{screenName}}</td>
<td>{{description}}</td>
<td>
<button action 'delete_friend' class="btn btn-danger">Delete</button>
</td>
</tr>
{{/each}}
</tbody>
</table>
</script>
Friends Partial Template (to allow entering new friend) :
<script type="text/x-handlebars" id="_newFriend">
<p> Add New Friend </p>
<table class="table table-bordered">
<tr>
<td><label for="name">Name: </label></td>
<td>{{input type="text" value=name id="name"}}</td>
</tr>
<tr>
<td><label for="screenName">Screen Name: </label></td>
<td>{{input type="text" value=screenName id="screenName"}}</td>
</tr>
<tr>
<td><label for="description">Description: </label></td>
<td>{{input type="text" value=description id="description"}}</td>
</tr>
</table>
</script>
Expenses Template :
<script type="text/x-handlebars" id="expenses">
{{#if isEditing}}
{{partial newExpense}}
<p>
<button {{action 'cancel'}} class="btn btn-success">Cancel</button>
<button {{action 'addExpense' 'addSummary'}} class="btn btn-info">Save</button>
</p>
{{else}}
<p><button {{action 'add_expense'}} class="btn btn-primary">(+) New Expense </button></p>
{{/if}}
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Date</th>
<th>Description</th>
<th>Who paid?</th>
<th>Amount</th>
<th>For whom?</th>
</tr>
</thead>
<tbody>
{{#each model}}
<tr>
<td>{{date}}</td>
<td>{{description}}</td>
<td>{{whoPaid}}</td>
<td>{{amount}}</td>
<td>{{forWhom}}</td>
</tr>
{{/each}}
</tbody>
</table>
</script>
Expenses partial template (to allow new expense) :
<script type="text/x-handlebars" id="_newExpense">
<p> Add New Expense </p>
<table class="table table-bordered">
<tr>
<td><label for="date">Date: </label></td>
<td>{{input type="date" value=date id="date"}}</td>
</tr>
<tr>
<td><label for="description">Description: </label></td>
<td>{{input type="text" value=description id="description"}}</td>
</tr>
<tr>
<td><label for="whoPaid">Who Paid: </label></td>
<td>{{input type="text" value=whoPaid}}</td>
</td>
</tr>
<tr>
<td><label for="amount">Amount: </label></td>
<td>{{input type="text" value=amount id="amount"}}</td>
</tr>
<tr>
<td><label for="forwhom">For Whom: </label></td>
<td>{{input type="text" value=forWhom id="forwhom"}}</td>
</tr>
</table>
</script>
Summary Template :
<script type="text/x-handlebars" id="summary">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Name</th>
<th>Total Expenses</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{name}}</td>
<td>{{totalExpenses}}</td>
</tr>
</tbody>
</table>
</script>

In the route model method you can query for models from others routes, like:
App.SummaryRoute = Ember.Route.extend({
model: function() {
return this.store.find('friends');
}
});
So inside of summary controller you can access the friends using this.get('model')
If you need to return more than one promise, you need to use Ember.RSVP.hash:
App.SummaryRoute = Ember.Route.extend({
model: function() {
return Ember.RSVP.hash({
friends: this.store.find('friend'),
expenses: this.store.find('expense'),
}).then(function(data) {
var friends = data.friends,
expenses = data.expenses;
// calculate the totalExpenses ...
// Fixed for simplicity
return { name: 'foo', totalExpenses: 12 }
});
}
});
So inside of summary controller you can access the friends using this.get('model.friends') and expenses with this.get('model.expenses').
If you have a router structure where your subroute needs to access the model from a parent route, like:
App.Router.map(function() {
this.resource('parent', function() {
this.route('child');
});
});
In the child route you will be able to use modelFor('parent') because the parent route already have your model resolved, for example:
App.ChildRoute = Ember.Route.extend({
model: function() {
return this.modelFor('parent')
}
})

Related

How to use multiple conditions using #if while forming a Table in ember JS?

I am forming a Table dynamically using Ember
How can i use nested if while forming the table
Something like this
{{#if ismorethanone && model.hasSize}}
<td> Hai </td>
{{else}}
<td> Bye </td>
{{/if}}
My code
<script type="text/x-handlebars" data-template-name="index">
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>Participant</th>
</tr>
</thead>
<tbody id="ParticipantList">
{{#each person in model}}
<tr>
<td> {{person.name}}</td>
<td> {{person.city}}</td>
{{#if ismorethanone}}
<td><img src="image.jpg" alt="Remove" {{action "removeUser" person.name}}></td>
{{/if}}
</tr>
{{/each}}
</tbody>
</table>
</script>
http://jsfiddle.net/6Evrq/1937/
Either use ember-truth-helpers:
{{#if (and ismorethanone && model.hasSize)}}
foo
{{else}}
bar
{{/if}
or just nest the ifs:
{{#if foo}}
{{#if bar}}
one
{{else}}
two
{{/if}}
{{/if}}

delete multiple records on EmberJS using {{input type="checkbox"}}

I would like to have an action that prints all the selected check-boxes on my table to the console.
in my controller I have
removedSelected: function() {
let selected = this.filterBy('isSelected', true);
console.log(selected);
}
in my template file I have
{{input type="checkbox" checked="isSelected"}}
I have setup my controller to filter all the records that are "isSelected" in the table by using input helper on ember.
I am getting an error on the console which states this.filterBy is not a function
Do i need to setup an array to handle this first?
Below is more of the code for a better picture.
Thanks!
// templates/warranty/index.hbs
<div class="container">
<h4>List</h4>
<div class="row">
<div class="col-sm-3">
<div class="control-group">
{{#link-to 'warranty.new' class="btn btn-primary btn-sm"}}New Claim{{/link-to}}
<button class="btn btn-primary btn-sm" {{action "toggleMultiple"}}>Select</button>
{{#if canDeleteMultiple}}<button class="btn btn-danger btn-sm"{{action "removedSelected" warranty}}>Delete Selected</button>{{/if}}
</div>
</div>
<div class="container">
<table class="table table-striped table-hover ">
<thead>
<tr>
{{#if canDeleteMultiple}}<th>Select</th>{{/if}}
<th>Action</th>
<th>Claim ID</th>
<th>Claim Status</th>
<th>Serial Number</th>
<th>Issue Description</th>
</tr>
</thead>
<tbody>
{{#each model as |warranty|}}
<tr>
{{#if canDeleteMultiple}}{{input type="checkbox" checked="isSelected"}}{{/if}}
<td>{{#link-to 'warranty.edit' warranty.id class='btn btn-success btn-xs'}}Edit{{/link-to}}<button class="btn btn-danger btn-xs" {{action "deleteWarranty" warranty}}>Delete</button></td>
<td>{{warranty.id}}</td>
<td>{{warranty.claimStatus}}</td>
<td>{{warranty.serialNumber}}</td>
<td>{{warranty.issueDescription}}</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
</div>
// app/controllers/warranty/index.js
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
toggleMultiple() {
this.toggleProperty('canDeleteMultiple');
},
removedSelected: function() {
let selected = this.filterBy('isSelected', true);
console.log(selected);
}
}
});
I have done this way, you can check the twiddle (https://ember-twiddle.com/aa88cd0442ec0d2219e792d58ab8b703?openFiles=templates.index.hbs%2Ctemplates.components.checkbox-component.hbs), same thing as mention by kumkanillam,
in your index.hbs i used checkbox as a component,
{{checkbox-component isChecked=warranty.isSelected action=deleteItems index=index}}{{/if}}
and in controller actions,
removedSelected: function() {
let selected = this.get('model').filterBy('isSelected', true);
console.log(selected);
}
In your hbs file,
{{input type="checkbox" checked=warranty.isSelected }}
OR
<input type="checkbox" checked={{warranty.isSelected}} onchange={{action (mut warranty.isSelected) value="target.checked" }}>
and in your controller,
removedSelected: function() {
let selected = this.get('model').filterBy('isSelected', true);
console.log(selected);
}

Submitting form from a modal in Ember

I am trying to make a registration page in ember which is opened when someone clicks the registration button. The registration page is opened in a modal. I used the modal implementation given on Ember websit
http://emberjs.com/guides/cookbook/user_interface_and_interaction/using_modal_dialogs/
Now the registration form opens on clicking the button but I am not able to catch the submit event of the registration form anywhere. You can refer to the code here:
http://jsfiddle.net/jywPL/1/
<script type="text/x-handlebars">
{{outlet}}
{{outlet modal}}
</script>
<script type="text/x-handlebars" data-template-name="index">
<h4>Register</h5>
{{outlet}}
<button {{action 'openModal' 'modal' model}}>Register</button>
</script>
<script type="text/x-handlebars" data-template-name="modal">
{{#modal-dialog action="close"}}
<form class="form-horizontal" {{action "register" on="submit"}}>
<br/>
<div align="center" >
<table class="table-hover">
<tr>
<td>
<label>First Name</label>
</td>
<td>
{{input value=firstName class="controls" type="text"}}
</td>
</tr>
<tr>
<td>
<label>Last Name</label>
</td>
<td>
{{input value=lastName class="controls" type="text"}}
</td>
</tr>
<tr>
<td>
<label>Email</label>
</td>
<td>
{{input value=email class="controls" type="text"}}
</td>
</tr>
<tr>
<td>
<label>Company</label>
</td>
<td>
{{input value=company class="controls" type="text"}}
</td>
</tr>
<tr>
<td>
<label>Company Contact</label>
</td>
<td>
{{input value=contact class="controls" type="text"}}
</td>
</tr>
<tr>
<td>
<label>Reason for request</label>
</td>
<td>
{{view Ember.TextArea valueBinding="reason" rows="10" cols="20"}}
</td>
</tr>
</table>
<br/>
<button type="submit">Register</button>
<button {{action "close"}}>Done</button>
</div>
</form>
{{/modal-dialog}}
</script>
<script type="text/x-handlebars" id="components/modal-dialog">
<div class="overlay" {{action "close"}}>
<div class="modal" {{action bubbles=false}}>
{{yield}}
</div>
</div>
</script>
var App = Ember.Application.create();
App.ApplicationRoute = Ember.Route.extend({
actions: {
openModal: function(modalName, model) {
this.controllerFor(modalName).set('model', model);
return this.render(modalName, {
into: 'application',
outlet: 'modal'
});
},
closeModal: function() {
return this.disconnectOutlet({
outlet: 'modal',
parentView: 'application'
});
},
register: function() {
alert('hello');
}
}
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return Em.Object.create({firstName: '',lastName: '',email:'',company:'',contact:'',reason:''});
},
action: {
register: function(){
alert('Registering');
}
}
});
App.ModalController = Ember.ObjectController.extend({
actions: {
close: function() {
return this.send('closeModal');
},
register: function(){
alert('hello1');
}
}
});
App.ModalDialogComponent = Ember.Component.extend({
actions: {
close: function() {
return this.sendAction();
},
register: function(){
alert('hello2');
}
}
});
.I have tried to trigger action helper called register on form submit but the register action is not triggered. From the modal implementation I see that the action bubbling has been disabled so the action wouldn't be triggered in any of the parent routes. But why is it not triggering in ModalDialogComponent actions tag.
In your ModalController Route, add
action: {
doRegister: function() {
this.register(); //or whatever
}
Then on the submit button
<button type="submit" {{action "doRegister"}}>Register</button>
If your ModalController Route is binding correctly, this should work.

Elegant way to select <tr> when a child <a> is active

Suppose I have the following partial template:
<script type="text/x-handlebars" data-template-name="_folderList">
<table id="folder-list">
<thead>
<tr class="PLEASE_MAKE_ME_ACTIVE_IF_SELECTED_ROW">
<th>Name</th>
<th>Date Created</th>
</tr>
</thead>
<tbody>
{{#each folder in controller}}
<tr>
<td>
{{#linkTo "folder" folder }}
<i class="icon-folder-close"></i> {{ folder.folder_name }}
{{/linkTo}}
</td>
<td style="padding-left: 15px;">
{{ prettyDate folder.created_date}}
</td>
</tr>
{{/each}}
</tbody>
</table>
</script>
Notice the class I've added to the table row element. How can I add an "active" class to this row when it's child link is the active link? Ember automatically adds the active link when the current route matches the element in the collection. I'm trying to find the elegant, "Ember way" of doing this without resorting to jQuery hacks.
While I'd still like to see an answer to the question as I originally stated it, the workaround I went with for now is not to use tables at all. I'm already using Bootstrap based CSS layouts for the rest of my site, so I decided to use a fluid layout instead of tables:
<script type="text/x-handlebars" data-template-name="_folderList">
<div id="folder-list">
<div class="container-fluid list-header">
<div class="row-fluid">
<div class="span5">Name</div>
<div class="span7">Date Created</div>
</div>
</div>
{{#each folder in controller}}
{{#linkTo "folder" folder }}
<div class="container-fluid list-item">
<div class="row-fluid">
<div class="span5">
<i class="icon-folder-close"></i> {{ folder.folder_name }}
</div>
<div class="span7">
{{ prettyDate folder.created_date}}
</div>
</div>
</div>
{{/linkTo}}
{{/each}}
</div>
</script>
This allows me to wrap the whole "row" with the anchor using {{#linkTo}} and style the whole row accordingly.
You can use bindAttr to toggle the classname. For example if you hold the state in an isSelected property in your controller then in the template.
<tr {{bindAttr class='isSelected:active'}}>
Where active is the css class name.

Action Helper in Ember JS not calling function

<a class="btn btn-primary" href="#" {{action "toggleStatus"}}><i class="icon-plus icon-white"></i> Add Staff</a>
This is in a view template called stafflist.handlebars. The content is as follows
<div class="page-header">
<h3>{{staff.title}} <small>List of users who has access to this application</small></h3>
</div>
<div class="commands pull-right">
sta
<a class="btn btn-primary" href="#" {{action "toggleStatus"}}><i class="icon-user icon-white"></i> {{staff.btnTitle}}</a>
</div>
<div class="pull-left">
<input type="text" class="search-query" placeholder="Search">
</div>
<table class="table table-striped table-bordered">
<thead>
<tr>
<td>NAME</td>
<td>ID</td>
</tr>
<thead>
<tbody>
{{#each staff}}
<tr>
<td>{{this.fname}}</td>
<td>{{this.id}}</td>
</tr>
{{/each}}
</tbody>
</table>
The View file is as below
App.StaffListView = Em.View.extend({
templateName:'sellap-web/~templates/stafflist',
staffBinding:'App.staffController',
toggleStatus: function() {
alert('Hurray');
}
});
When clicking the button, the action is never calling the alert. What is going wrong here. I am using ember-skeleton to compile.
Found the culprit. My App.create has a method called init. I changed the name to something else and now it works fine. I didnt call the super.