Listing multiple items using EmberJS 2.0 - ember.js

I have a basic app having using the Fixture Data Adapter and have a model with some basic seed data.
I am having an issue getting the new emberjs 2.0 to list multiple items in a model. The objects are loaded and showing in them ember inspector but are not looping through and displaying in the browser. I have been able to list one at a time but when i switch to adding multiple items it is blank. Any help would be great.
I have updated with some more information. Here is the route for the list i am trying to list out.
<!--dashboard/route.js -->
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.findAll('dashboard');
}
});
Here is the template file
<!-- dashboard/template.hbs -->
<tbody>
<tr>
{{#each dashboards as |dashboard|}}
<td>dashboards.status</td>
<td>dashboards.orderid</td>
{{/each}}
</tr>
</tbody>
I think I have everything setup right but cant get it to work.
Thanks!

Give this a try for the model hook. It doesn't need to be a hash.
model: function() {
return this.store.findRecord('dashoard', 2);
}
And if you want to return all the dashboards
model: function() {
return this.store.findAll('dashoard');
}
Then in dashboard/template.hbs
{{order-list dashboards=model}}
Now you have access to all your dashboards in your component
{{#each dashboards as |dashboard|}}
<td>dashboard.status</td>
<td>dashboard.orderid</td>
{{/each}}

When you fetch something in a model, it sets the model property on the respective controller.
So, instead of looping through dashboards, you need to do this:
<tbody>
<tr>
{{#each model as |dashboard|}}
<td>dashboards.status</td>
<td>dashboards.orderid</td>
{{/each}}
</tr>
</tbody>
An alternative is to use the setupController hook to set up the dashboards property on the controller. Something like this:
setupController (controller, model) {
this._super(...arguments)
controller.set('dashboards', model)
}
This isn't necessary; you're basically creating a dashboards alias that points to model. So, now, when you loop through dashboards, it loops through the model.
You can find more about how a controller is set up here: http://guides.emberjs.com/v2.0.0/routing/setting-up-a-controller/

Related

Display a subset of model data in emberjs

I have the following in my routes
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.query('post',{published:true});
}
});
and a post-viewer component that renders the model. the problem that i am facing with is filter. How can i implement the same without loading the models each time. Currently i am just passing the models in the component and using the following
{{#each posts as |item|}}
{{/each}}
To render the elements. What is the proper way by which lets say i can filter them based on title containing some specific keyword. I tried using this.store.query inside the each loop but that did not work out.
If you use this.store.query ember does not cache the result. So probably you should use a .findAll() and then filter the data on the client side. A simple way to do so is inside your model() hook:
return this.store.findAll('post')
.then(posts => posts.filter(post => get(post, 'published') === true));
This will work because ember-data does cache the result of the findAll() and the filter executes on the client. You can do the same with a computed property. This has some benefits, as, for example, you can filter based on another property. A computed property in your controller for example:
filteredModel: Ember.computed('model.#each.name', 'searchName', {
get() {
return get(this, 'model').filter(record => get(record, 'name') === get(this, 'searchName'));
}
});
You can use
https://github.com/DockYard/ember-composable-helpers
and filter/filterBy
filter -Filters an array by a callback.
{{#each (filter (action "isActive") users) as |user|}}
{{user.name}} is active!
{{/each}}
filter-by Filters an array by a property.
{{#each (filter-by "isActive" true users) as |user|}}
{{user.name}} is active!
{{/each}}
If you omit the second argument it will test if the property is truthy.
{{#each (filter-by "address" users) as |user|}}
{{user.name}} has an address specified!
{{/each}}
You can also pass an action as second argument:
{{#each (filter-by "age" (action "olderThan" 18) users) as |user|}}
{{user.name}} is older than eighteen!
{{/each}}
P.S.
Another variant ( pure Ember.js ) - create computed property and iterate over it. And inside computed property filter items

Ember Data and Firebase Where is my Id

I'm having trouble understanding how to update a record in an Ember.js that uses EmberFire and Firebase.
I have a small test application built to try to understand all of the CRUD functions. I can return a list of tasks that have been created, create a new task, and delete a task. But I cannot correctly update a record in a list.
When I look in the inspector, on my index page, I see that in the Ember debugger, under Data, it shows my model, and there is an Id field that contains the value that Firebase generated when a record was created on the server.
But when I console log the object that is getting passed to my Update Action in the route, there is no Id attribute. I think that is why I get an error of:
Error: no record was found at https://taskline.firebaseio.com/tasks/id
When hitting this piece of code:
export default Ember.Route.extend({
model: function () {
return this.store.findAll('task');
},
actions: {
updateTask: function (model) {
console.log(JSON.parse(JSON.stringify(model)));
this.store.findRecord('task', 'id').then(function(task){
task.set( 'taskname', model.taskname);
task.set( 'startdate', model.startdate);
task.set( 'enddate', model.enddate);
task.set( 'banding', model.banding);
return task.save();
});
},
Ember Fire is supposed to handle the Id isn't it? But if it's not in my model object, how am I supposed to pass it to the find query?
When you would like to update a model, one of the best option to pass the record back from the template/controller to the route action. In this case the record will be ready in your function param, so your updateTask method would look like this (only):
updateTask(record) {
record.save();
}
The whole process:
Firstly, in the Route handler download all records, as you did in your example, and implement the action:
import Ember from 'ember';
export default Ember.Route.extend({
model() {
this.store.findAll('task');
},
actions: {
updateTask(task) {
task.save();
}
},
});
Secondly, in your template list each task with input box. Maybe it could be a table. (I just have one field here taskname, but you could have more, of course.)
<table>
<thead>
<th>ID</th>
<th>Taskname</th>
<th>Action</th>
</thead>
<tbody>
{{#each model as |task|}}
<tr>
<td>{{task.id}}</td>
<td>{{input value=task.taskname}}</td>
<td><button {{action 'updateTask' task}}>Update</button>
</tr>
{{/each}}
</tbody>
</table>
As you see, you are sending back the task record to the updateTask action in your route, so we are able to save it immediately. You can learn all these tricks in this free tutorial, which focuses on the Ember Way and uses Firebase: http://yoember.com

How to create an external link from emberjs loop?

I'm looping through several items in a model. For each item I would like to create an external link to a page in my application that is not using emberjs. I thought this would be trivial but its not working the way I thought it would work.
This is what I have:
<tbody>
{{each model itemViewClass=App.ColorView}}
</tbody>
<script type="text/x-handlebars" id="colorTemplate">
<tr>
<td>{{date}}</td>
<td>{{name}}</td>
</tr>
</script>
App.ColorView = Em.View.extend({
templateName: 'colorTemplate'
});
I thought this would create links like these:
/myapp/colors/5/shades
/myapp/colors/45/shades
/myapp/colors/6/shades
...etc.
However, the link is being created like this:
localhost:8080/myapp/colors/%3Cscript%20id='metamorph-33-start'%20type='text/x-placeholder'%3E%3C/script%3E56%3Cscript%20id='metamorph-33-end'%20type='text/x-placeholder'%3E%3C/script%3E/shades
You Should implement a itemController to the {{#each}} collection view. In that itemController you can use a computed property to generate the url as
url : function () {
return "/myapp/colors/"+this.get('id')+"/shades";
}.property()
Here is a Sample Bin
Hope it helps
you should use {{bindAttr href="url"}} for this. url is a method that generates url

deleteRecord doesn't update ArrayController when Model is filtered

I am using a simple Ember.ArrayController in an application with ember-data (latest), ember rc6 and a stock REST controller.
I have delete actions next to each item in the list rendered by the array controller. When an item is deleted, the proper REST API call is made and it's removed from the database properly. Server responds with the correct 204 response.
Here is my router setup, notice the find filter being applied
App.CategoriesIndexRoute = Ember.Route.extend({
setupController : function(controller, model) {
this._super(controller, model);
controller.set("content", App.Category.find({
"parent": null,
}));
}
});
If I remove the find filter and load all categories, everything works fine (item is automatically removed from the list immediately after commit). However, when I add the filter to only display categories that don't have a parent, the list is not updated when an item is deleted. If I transition to another section and come back, the list is reloaded and the category is gone.
Here is deleteCategory method in the ArrayController:
deleteCategory: function(category) {
var transaction = this.get("store").transaction();
transaction.add(category);
category.deleteRecord();
transaction.commit();
}
Is this an ember-data or emberjs bug? If not, what am I doing wrong here? If it's a bug, is there a way to force-reload the ArrayController contents after I delete an item? Alternatively, can I remove the category from the ArrayController manually?
UPDATE 1:
I managed to force-update the array controller's contents by setting its content:
category.one("didDelete", this, function() {
this.set("content", App.Category.find({
parent: parent_category
}));
});
UPDATE 2:
Here is how I am displaying the list of items in the template:
{{#each category in controller.content }}
<tr>
<td><a {{ action "detailCategory" category }}>{{ category.name }}</a></td>
<td><a {{ action "deleteCategory" category }}>Delete</a></td>
</tr>
{{/each}}
Thank you!
This is no longer the way to do things in Ember Data. One would not use transactions any longer, as can be seen in the transition doc: https://github.com/emberjs/data/blob/master/TRANSITION.md

Controller not seeing the updated model - asynchronous handling

I have a very simple requirement but like with many things in Ember.JS, I'm banging my head against the wall trying to get it implemented.
I have an overview screen where a couple of records are displayed in a table.
To render the overview screen I'm using the following Route
App.LocationsIndexRoute = Ember.Route.extend({
setupController: function(controller) {
var locations = App.Location.find();
controller.set('content', locations);
},
renderTemplate: function() {
this.render('locations.index',{into:'application'});
}
});
This is working fine.
I would now like to conditionally render the overviewtable.
If records are present render the table.
If no records are present display a message.
I tried implementing this using the following controller.
App.LocationsIndexController = Ember.ArrayController.extend({
locationsPresent: function() {
var model = this.get('content');
return model.content.length > 0;
}.property()
});
and the following template
{{#if locationsPresent}}
<table class="table table-hover">
<tr>
<th>Latitude</th>
<th>Longitude</th>
<th>Accuracy</th>
<th></th>
<th></th>
</tr>
{{#each location in model}}
<tr>
<td>{{location.latitude}}</td>
<td>{{location.longitude}}</td>
<td>{{location.accuracy}}</td>
<td>{{#linkTo locations.edit location}}Edit{{/linkTo}}</td>
<td><button {{action removeItem location}}>Delete</button></td>
</tr>
{{/each}}
</table>
{{else}}
No locations present.
{{/if}}
The computed locationsPresent property is called once, before the page is rendered. At that time I assume that the model is still being loaded as the length = 0.
When the page is rendered, the locations from the App.Locations.find() are available but the locationsPresent is not called anymore, meaning the page decided to render the No locations present. message.
I went through the Managing Asyncrony in Ember page and assumed that the computer property locationsPresent would be updated if the underlying model changed (if it was completely loaded) as the page states :
Using a computed property for author eliminated the need to explicitly invoke the computation in a callback when the underlying property changed.
I'd love to know what I'm doing wrong and how I can fix this but more importantly why I seem to be missing some of these core concepts of Ember.JS. If somebody can point me where in the docs / guides this is explained properly I'd love to know.
I think it is a easy fix. You need to add the property you are observing. like so:
locationsPresent: function() {
var length = this.get('content.length');
return length > 0;
}.property('content.#each')
adding the #each is necessary if locationsPresent needs to recalculate wen content is added. I think you can also observe 'content.isLoaded'