Ember.js: Grouping/partitioning an ArrayController - javascript

I have an ArrayController, and I would like to group the contents of that ArrayController based on a the value of a specific key.
For example, if the objects in my ArrayController are:
id status name
-----------------------------
1 1 some name
2 1 some other name
3 2 blah
4 3 blah again
Then I would like to group the contents by status.
To do this, I tried using computed properties in my ArrayController:
App.SomeArrayController = Ember.ArrayController.extend({
itemController: 'some-item',
status1: Ember.computed.filterBy('content', 'status', 1),
status2: Ember.computed.filterBy('content', 'status', 2),
status3: Ember.computed.filterBy('content', 'status', 3)
});
In the template, these are being displayed, but they are not being wrapped by the itemController I specified in the ArrayController:
// item controller used in the ArrayController
App.SomeItemController = Ember.ObjectController.extend({
anotherKey: function () {
return 'hey ' + this.get('name');
}.property('name')
});
<!-- template to display status=1 items -->
{{#each status1}}
// displays the name (as a property from the model)
{{this.name}}
// nothing displays here
// (leading me to believe it is not being wrapped by the item controller)
{{this.anotherKey}}
{{/each}}
What am I doing wrong?

itemController only wraps items when you iterate over the controller collection.
{{#each item in controller}}
{{item.coolItemControllerProperty}}
{{/each}}
It doesn't apply to any collection within the controller. If you tried to iterate the underlying model/content it wouldn't be wrapped.
{{#each item in content}}
{{item.coolItemControllerProperty}} // undefined
{{/each}}
{{#each item in model}}
{{item.coolItemControllerProperty}} // undefined
{{/each}}
fortunately you can specify an itemController in your template for these situations.
{{#each item in status1 itemController='some-item'}}
{{item.coolItemControllerProperty}}
{{/each}}

Related

If equals validate in handlebar template inside each loop

I have a php array like this one
bookings[] = {"arrived","cancelled","departed"};
When display this array in handlebars template i want to check IF equal condition.
In the following example when value is equals to cancelled i want to display some text.
{{#each bookings}}
{{#if this.value cancelled}}
cancelled
{{/if}}
{{/each}}
This code is not working. What is alternative IF equals condition for handlebars to execute in loop.
Now my code is working,
bookings = ["arrived", "cancelled", "departed"];
Handlebar function:
Handlebars.registerHelper('check_status', function(val1, val2) {
return val1 === val2;
});
Handlebar template:
{{#if (check_status this 'cancelled')}}
If I'm not mistaken you can't do an actual conditional in handlebars, you can only do if true/false which means that the **value** in {{#if **value**}} need to either be true or false
So what you will want to do is in the area of code where this.value is defined create a function like this
valueIsCancelled = function(value) {
return value === 'cancelled';
}
In your template you will do:
{{#each bookings}}
{{#if this.valueIsCancelled this.value}}
cancelled
{{/if}}
{{/each}}
or another option is to define another variable where value is defined that would be a boolean
var isCancelled = value === 'cancelled';
and your template would look like this
{{#each bookings}}
{{#if this.isCancelled}}
cancelled
{{/if}}
{{/each}}

Meteor - display collection with conditions

I have a user based Meteor application with a collection representing groups.
A group is something like this:
{ name: groupname, members: [memberuseridlist], owner: owneruserid}
I have a template for these groups that looks like this:
{{#each groups}}
<li>{{name}}
-
<button class="join">+</button>
<button class="leave">-</button>
<button class="delete">x</button>
</li>
{{/each}}
But I'd like to ensure that only the relevant buttons are displayed e.g.:
{{#each groups}}
<li>{{name}}
-
{{#unless ismember}}<button class="join">+</button>{{/unless}}
{{#if ismember}}<button class="leave">-</button>{{/if}}
{{#if isowner}}<button class="delete">x</button>{{/if}}
</li>
{{/each}}
I have a set of template helper methods but I don't understand how to pass the actual group into the function, so that I can evaluate ismember and isowner for each group.
The context within {{#each groups}} is a group document. So within your helpers you can use this to mean a group. Try something like this:
Template.myTemplate.helpers({
ismember: function() {
return _.contains(this.memberuseridlist, Meteor.userId());
},
isowner: function() {
return this.owner === Meteor.userId();
}
});
If you wish to make these helpers more portable between your templates, see my article on models.

How to convert a Array Object to EmberJS Array

I've the following class:
App.Entity = Ember.Object.extend({
id: null,
name : null,
});
And I've the following controller :
App.HomeController = Ember.ObjectController.extend({
entities: null,
init:function(){
var myArray = [];
var a = App.Entity.create();
a.set('id',1);
a.set('name','A');
var b = App.Entity.create();
b.set('id'2);
b.set('name','B');
//and I add another entities dynamycally
myArray.push(a);
myArray.push(b);
console.log( 'isArray: '+ Ember.isArray(myArray) ); //I get true
this.set('entities', myArray );
}
});
The problem is when I try to iterate and render the content over view:
<script type="text/x-handlebars" data-template-name="home" >
{{#if entities}}
{{#each entities }}
{{this.value}}
{{/each}}
{{/if}}
{{outlet}}
</script>
I get the following mistake:
Assertion Failed: The value that #each loops over must be an Array. You passed <App.Entity:ember425>,<App.Entity:ember426>,...
How to fix it?
After reading a bit in their documentation, I have understood that you should use Ember.ArrayController to render arrays.
An example from their documentation would be like this:
Controller:
MyApp.listController = Ember.ArrayController.create();
$.get('people.json', function(data) {
MyApp.listController.set('content', data);
});
Template:
{{#each MyApp.listController}}
{{firstName}} {{lastName}}
{{/each}}
As can be seen here, they first set the key content with the data array directly on the controller. In your case this would be the step this.set('entities', myArray ); that you already did.
In the second step, they use the #each helper on the controller, not the key. In your case this would look like:
<script type="text/x-handlebars" data-template-name="home" >
{{#if entities}}
{{#each App.HomeController }}
{{id}} {{value}}
{{/each}}
{{/if}}
{{outlet}}
</script>
To access the properties you do it as in any handlebars template.
Update
From your comments I assume that you are not deserializing the json string to a javascript object.
The json you receive from the server is a plain string. You must deserialize it using JSON.parse.
Example :
var json = '[{"id":"17","nombre":"Musical dezzer"},
{"id":"172","nombre":"Musical dezzer"}]',
trueResult = JSON.parse(json);
console.log(trueResult);

Emberjs model rendering

I just started learning emberjs and wanted to display a list of data from the models. My app.js:
var h= [{
name: "Hi",
},
{
name: "Hello",
}
];
App.ListsRoute = Ember.Route.extend({
model: function(){
return h;
}
});
my corresponding lists handlebar:
<div id="list">
<ul>
{{#each}}
<li>
{{ name }}</li>
{{/each}}
</ul>
</div>
I get the error as:
Error: Assertion Failed: The value that #each loops over must be an Array. You passed (generated lists controller)
What is that I can do to display those?
#each wants to iterate over a list. Since you didn't give it an argument, it defaults to trying to iterate over your ListsController. Unfortunately, since you didn't define it, the controller was auto-generated based on the plain Ember.Controller. Thus, the error.
Two ways to fix this:
1) Make ListsController into an ArrayController
App.ListsController = Ember.ArrayController.extend({});
2) Tell #each to target your model instead of controller.
<div id="list">
<ul>
{{#each model}}
<li>{{ name }}</li>
{{/each}}
</ul>
</div>

meteor: render a template in a specific context

I have two templates
<body>
{{>tmpl1}}
{{>tmpl2}}
....
</body>
in the tmpl1 I have a list of items, which can be clicked. When one is click, tmpl2 shown the details. How can this be achieved ?
So, just to make the idea clearer, here is how I get the list of items
Template.tmpl1.items = function () {
return Items.find({}).fetch();
};
tmpl1 displays them as follows
<template name="tmpl1">
{{#each items}}
{{title}}
{{/each}}
....
</template>
So tmpl2 template might look like this
<template name="tmpl1">
<h1>{{title}}</h1>
<p>{{content}}</p>
</template>
Any suggestions how to link the selected item in tmpl1 with tmpl2 ?
First, put your templates in a container so that you can manipulate the context. Also, put the details template in a #with context:
<template name="box">
{{> list}}
{{#with item}}
{{> details}}
{{/with}}
</template>
Now, add the event handlers for the box template. Assuming your entries in the list looks like this:
<div class="listItem" data-id="{{_id}}">{{title}}</div>
Write the handler:
Template.box.events({
'click .listItem': function(e, t) {
t.data.itemId = $(e.target).data('id');
t.data.itemDep.changed();
}
});
Finally, create the data helper and dependency for the selected item:
Template.box.created = function() {
this.data.itemDep = new Deps.Dependency();
};
Template.box.item = function() {
this.itemDep.depend();
return Items.findOne(this.itemId);
};

Categories