ember link-to from the component - templates

i am new at EmberJs.
I tried to link from the component "invoices-list" to invoice.
invoices-list.hbs
{{#each invoices as |invoice|}}
<tr>
<td>{{invoice.kdnr}}</td>
<td>{{invoice.rnr}}</td>
<td>{{invoice.invoiceId}}</td>
<td>**{{#link-to 'invoice' invoice.invoiceId}}Click here{{/link-to}}**</td>
</tr>
{{else}}
<p>No datas</p>
{{/each}}
invoices.hbs
{{invoices-list invoices=model}}
router.js
Router.map(function() {
this.route('invoices');
this.route('invoice', { path: '/invoice/:invoice_id' });
});
My problem is, the template will not rendered and i get the error: "props.parentView.appendChild is not a function"
What is wrong?
Thanks for help.
Fabian

Let me give you first an example how to use Link-to
Suppose this is your Route.js
Router.map(function() {
this.route('photos', function(){
this.route('edit', { path: '/:photo_id' });
});
});
and this is app/templates/photos.hbs
<ul>
{{#each photos as |photo|}}
<li>{{#link-to "photos.edit" photo}}{{photo.title}}{{/link-to}}</li>
{{/each}}
</ul>
then rendered HTML would be
<ul>
<li>Happy Kittens</li>
<li>Puppy Running</li>
<li>Mountain Landscape</li>
</ul>
so in your case this is Route
Router.map(function() {
this.route('invoices');
this.route('invoice', { path: '/invoice/:invoice_id' });
});
then you may use this
{{#each invoices as |invoice|}}
<tr>
<td>{{invoice.kdnr}}</td>
<td>{{invoice.rnr}}</td>
<td>{{#link-to 'invoice' invoice}}{{/link-to}}</td>
</tr>
{{else}}
<p>No datas</p>
{{/each}}
another example to clarify:
//Route.js
this.route('contacts');
this.route('contact', { path: 'contacts/:contact_id' });
//Contacts.hbs
{{#each model as |contact|}}
<tr>
<td>{{link-to contact.name 'contact' contact}}</td>
<td>{{link-to contact.email 'contact' contact}}</td>
<td>{{contact.country}}</td>
</tr>
{{/each}}
Hope it works for you. more info.

Related

Ember.JS - toggleProperty toggling all items in list

I have a toggleProperty in the container to toggle a set of actions on each item. The problem is, when the toggle button on 1 item is clicked, every item is toggled, instead of the one that's clicked.
I would love to know how to toggle only the clicked item, not everything from the list.
I am using the ember-cli to build my application.
My category model:
import DS from 'ember-data';
export default DS.Model.extend({
pk: DS.attr('string'),
category: DS.attr('string'),
products: DS.hasMany('product'),
});
My category route:
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.findAll('category');
},
});
My category controller
expand: function() {
this.toggleProperty('isExpanded', true);
}
My template:
{{#each model as |i|}}
<tr>
<td>
<a {{action 'expand'}}>{{i.category}}</a>
</td>
<td>
{{i.pk}}
</td>
<td>
{{#if isExpanded}}
<button {{action "deleteCategory"}}>Edit</button>
<button {{action "deleteCategory"}}>Delete</button>
{{else}}
<button {{action 'expand'}}>Actions</button>
{{/if}}
</td>
</tr>
{{/each}}
Since stackoverflow, is not letting me post without adding more text, I would also like to know how to show all the products associated with the category, on the same route (same page), by clicking on each category?
Cheers and thank you.
In controller:
expand(item) {
if (!item) {
return;
}
item.toggleProperty('isExpanded', true);
}
Template:
{{#each model as |i|}}
<tr>
<td>
<a {{action 'expand' i}}>{{i.category}}</a>
</td>
<td>
{{i.pk}}
</td>
<td>
{{#if i.isExpanded}}
<button {{action "deleteCategory"}}>Edit</button>
<button {{action "deleteCategory"}}>Delete</button>
Products:
{{#each i.products as |product|}}
{{product}}
{{/each}}
{{else}}
<button {{action 'expand' i}}>Actions</button>
{{/if}}
</td>
</tr>
{{/each}}

How should I handle an errors from server in Ember.js?

I have a small app, written using ember.js, that talks to REST API using RESTAdapter and displaying elements in list using ArrayController. When I'm performing a POST request to server and the responds with code 201 (Created) and a model with id the new models is displayed in list. But if server returns code 409 (Conflict) with the payload that looks like this
{
'errors': ['Error description']
}
I expect that model will not be added to list, but it isn't so. The model is still added to list, but without ID.
I found out that this model can be removed in multiple ways, but I don't know which of them is right.
So the questions are:
What is the right way to handle errors in this case (when you are using ArrayController and RESTAdapter)?
Is it possible to prevent model showing up in list if server returns 4xx code?
Here is code that I use now:
App.Usergroup = DS.Model.extend({
name: DS.attr('string'),
description: DS.attr('string'),
});
App.UsergroupsListController = Ember.ArrayController.extend({
needs: ['usergroups'],
allUsergroups: Ember.computed.alias('controllers.usergroups'),
itemController: 'usergroup'
});
App.UsergroupController = Ember.ObjectController.extend({
actions: {
removeGroup: function() {
var group = this.get('model');
group.deleteRecord();
group.save();
}
}
});
App.UsergroupsController = Ember.ArrayController.extend({
actions: {
addUsergroup: function() {
var model = this.get('model');
var group = this.store.createRecord('usergroup', {
name: model.name,
description: model.description
});
group.save().then(function() {
},
function(error){
group.rollback();
});
this.transitionTo('usergroups.index');
}
}
});
And here is the template excerpt:
<script type="text/x-handlebars" id="usergroups">
<div class="header">
<h1>User groups list</h1>
</div>
<div class="content">
<form class="pure-form">
<fieldset>
{{input valueBinding="model.name" placeholder="Name"}}
{{input valueBinding="model.description" placeholder="Description"}}
<button type="submit" {{action 'addUsergroup'}} class="pure-button pure-button-primary">Add</button>
</fieldset>
</form>
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" id="usergroups-list">
{{#if model}}
<table class="pure-table pure-table-striped">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Description</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{{#each}}
<tr>
<td>{{id}}</td>
<td>{{name}}</td>
<td>{{description}}</td>
<td><button class="pure-button" {{action "removeGroup"}}><i class="fa fa-trash"></i> Remove</button></td>
</tr>
{{/each}}
</tbody>
</table>
{{else}}
<p>No user groups.</p>
{{/if}}
</script>
Ember provides an error route and a loading route
Read more about it here - Ember error route
So when the Usergroup model throws an error, Ember will look for UsergroupErrorRoute or
usergroup/error template.
What you can do is you can have
<script type="text/x-handlebars" data-template-name="usergroup/error">
{{message}}
<script>
where {{message}} is transferred from the route
So, as I found out, errors should be handled in Route.
Currently my route looks like this:
App.UsergroupsRoute = App.AuthenticatedRoute.extend({
model: function() {
return this.store.find('usergroup');
},
redirectToLogin: function(transition) {
var loginController = this.controllerFor('login');
loginController.set('attemptedTransition', transition);
this.transitionTo('login');
},
actions: {
error: function(reason, transition) {
if (reason.status == 401) {
this.redirectToLogin(transition);
}
else {
alert('Something went wrong');
}
}
}
});
It works just fine and does what it should. But now I cannot get what is a reason for placing errors handling in Route?

template rendering is not working properly in ember js

I am very new to Ember js. when i route one template to another it working properly.but the problem is when i was render same template it won't work.
My code is follows:
index.html:Manager template in index.html
<script type="text/x-handlebars" data-template-name="manager">
{{#each model.manager}}
<div class="pure-g-r content-ribbon">
<div class="pure-u-1-3">
<div class="img-viewer-profile">
<img {{bindAttr src="image"}}>
</div>
</div>
<div class="pure-u-2-3">
<div class="l-box">
<h4 class="content-subhead">{{name}}</h4>
<table class="pure-table">
<tbody>
<tr class="pure-table-odd">
<td>Id</td>
<td><b>ATL-{{id}}</b></td>
</tr>
<tr class="pure-table-odd">
<td>Team</td>
<td><b>{{team}}</b></td>
</tr>
<tr>
<td>Division</td>
<td><b>{{division}}</b></br>
</tr>
<tr class="pure-table-odd">
<td>Manager</td>
<td>
<b>
<a href="#" {{action "managerinfo" manager_id}}>
{{manager_name}}
</a>
</b>
</td>
</tr>
{{/each}}
<tr>
<td>Reportees</td>
<td>
{{#each model.results}}
<br><b>
<a href="#" {{action "profileinfo" id}}>
{{reportees}}
</a>
</b></br>
{{/each}}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
{{outlet}}
</script>
app.js:
=========
App.ManagerController = Ember.ObjectController.extend({
manager_id: '',
id: '',
actions:{
managerinfo: function(manager_id) {
// the manager id of selected manager field
var manager_id = manager_id;
alert("profile");
alert(manager_id);
managerdata = $.ajax({
dataType: "json",
url: "/manager?manager_id=" + manager_id,
async: false}).responseJSON
managerdata.manger_id = manager_id;
console.log(managerdata);
this.transitionToRoute('manager', managerdata);
}
)}
Now my problem is when render the new manager data to manager it wont be displayed.
After refresh only it shows the data.
what mistake i was done in this code , i dont understand.so please provide me solution.
i added my complete code here with proper tags order.
As per your comment, the way you are doing is not suggested. You can pass manager_id in the route url. I will give you very basic skeleton which you can make further changes. Do remember, if you want to set model data from ajax, use model hook in the route
First Router
App.Router.map(function() {
this.resource("managers", function(){
this.route("all");
this.route("manager", { path: "/:manager_id" });
});
});
So here with #/manager/all displays all managers list
#/manager/:manager_id displays manager with id manager_id
Next ManagerAll route
App.ManagersAllRoute = Ember.Route.extend({
model: function() {
//do ajax and return managers data which sets as model for this route
}
});
sameway
App.ManagersManagerRoute = Ember.Route.extend({
model: function(params) {
//do ajax and return managers data which sets as model for this route
//here params will have the manager_id passed through url
//as it is ajax, create a promise
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.$.ajax({
dataType: "json",
url: "/manager?manager_id=" + params.manager_id,
async: false}).then(function(data){
resolve(data);
})
});
}
});
Next is template for managers
{{#each model.manager}}
{{#link-to 'managers.manager' manager_id}}{{{manager_name}}{{/link-to}}
{{/each}}
Now a template for manager
{{manager_id}}
{{manager_name}} blah blah blah
You didn't close the each tag properly.
<script type="text/x-handlebars" data-template-name="manager">
{{#each model.manager}}
<a href="#" {{action "managerinfo" manager_id}}>
{{manager_name}}
</a>
{{/each}}
</script>
Also you haven't closed the ManagerController correctly in the given above. Double check that.
App.ManagerController = Ember.ObjectController.extend({
manager_id: '',
id: '',
actions:{
managerinfo: function(manager_id) {
// the manager id of selected manager field
var self=this;
var manager_id = manager_id;
alert("profile");
alert(manager_id);
managerdata = $.ajax({
dataType: "json",
url: "/manager?manager_id=" + self.manager_id,
async: false}).responseJSON.then(function(managerdata) {
managerdata.manger_id = self.manager_id;
console.log(managerdata);
this.transitionToRoute('manager', managerdata);
})
}
)}

Ember.js dynamic link

I need some information about the {{link-to}} on ember. I've made some test and there is something I really don't understand..
Example :
I have a blog with with different post like that :
App.Router.map(function() {
this.resource('login', { path: '/' });
this.resource('home');
this.resource('posts', function(){
this.resource('post', { path: '/:post_id' }, function(){
this.route('update');
});
this.route('create');
});
});
Let's say that I have this template :
<script type="text/x-handlebars" data-template-name="enquiries">
<table>
<thead>
<tr>
<th>id</th>
<th>type</th>
<th>name</th>
<th>last update</th>
<th>Detail</th>
</tr>
</thead>
<tbody>
{{#each post in model}}
<tr>
<td>{{post.id}}</td>
<td>{{post.type}}</td>
<td>{{post.name}}</td>
<td>{{post.updatedAt}}</td>
<td>{{#link-to 'post' post}}View{{/link-to}}</td>
</tr>
{{/each}}
</tbody>
</table>
</script>
My simple post template
<script type="text/x-handlebars" data-template-name="post">
<div class="post-info">
<button {{action "update"}}>Update</button>
<table>
<tr>
<td>{{title}}</td>
</tr>
<tr>
<td>{{content}}</td>
</tr>
<tr>
<td>{{author}}</td>
</tr>
</table>
</div>
</script>
Those link a dynamic one and there is on all of them the good url such as localhost/posts/1 or 2 etc...
When I click on the link, nothing happend. I have to had {{oulet}} to show it. but my problem is that its show on the same page as my table (underneath), but I wanted to only display the post template..
I have some trouble to understand why, and also what is the main purpose of the outlet in my case...
Thanks.
The reason the post is shown within the posts template is because your Router defines it that way. If you want a separate page, try this:
App.Router.map(function() {
this.resource('login', { path: '/' });
this.resource('home');
this.resource('posts');
this.resource('post', { path: 'posts/:post_id' }, function(){
this.route('update');
});
this.route('create');
});
When you have a nested resource, the {{outlet}} helper designates where the nested template will be rendered.

How to use sortProperties: ['lastName']

I'd like to sort an Array or users which gets fetched by ember-data. I can't figure out to sort the array be lastName. The following code doesn't do the job. How can I fix it?
app.js
App.UsersRoute = Ember.Route.extend({
model: function() {
return App.User.find();
}
});
App.UsersController = Ember.ArrayController.extend({
sortProperties: ['lastName'],
sortAscending: true
})
index.html
<script type="text/x-handlebars" data-template-name="users">
<table class='table table-striped'>
{{#each model itemController="user"}}
<tr>
<td>{{lastName}}</td>
</tr>
{{/each}}
</table>
</script>
Kudos to Bradley Priest for answering the question. Using this in the template does the trick.
index.html
<script type="text/x-handlebars" data-template-name="users">
<table class='table table-striped'>
{{#each this itemController="user"}}
<tr>
<td>{{lastName}}</td>
</tr>
{{/each}}
</table>
</script>