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>
Related
Using Meteor, I have a collection for Contacts which I list with a checkbox beside each contact.
I want to be able to select multiple checkboxes and then click a button to delete the selected contacts from the Contacts collection.
With the code I have below, the selected _ids show up in an array in the console, but nothing is being deleted and no error is being produced.
contacts.html
<template name="contacts">
<h1>Contacts</h1>
<ul>
{{#each contacts}}
{{> contact}}
{{/each}}
</ul>
<br/>
Create Contact
<a class="delete-selected" href="">Delete Selected Contacts</a>
</template>
contact.html
<template name="contact">
<li style="list-style:none;">
<input id="{{_id}}" type="checkbox" value="{{_id}}" name="contact"/>
<span class="contact">{{firstName}} {{lastName}} <strong>{{company}}</strong></span> {{#if contactType}}({{contactType}}){{/if}}
</li>
</template>
Client JS
Template.contacts.events = {
'click .delete-selected': function(e) {
e.preventDefault();
var selectedContacts = [];
$('input[name=contact]:checked').each(function() {
selectedContacts.push($(this).val());
});
Meteor.call('removeSelectedContacts', {selectedContacts: selectedContacts});
}
Server JS
Meteor.methods({
removeSelectedContacts: function(selectedContacts) {
Contacts.remove({_id:{$in:[selectedContacts]}})
//Contacts.remove({selectedContacts});
console.log(selectedContacts);
}
});
Thanks
#corvid: I think you can only remove one at a time on the client (by _id)
#serks: you have an extra array level in there, in your method just do:
Contacts.remove({ _id: { $in: selectedContacts }});
There's also an error in how you're calling the Method, instead of:
Meteor.call('removeSelectedContacts', {selectedContacts: selectedContacts});
Simply pass the parameter directly:
Meteor.call('removeSelectedContacts',selectedContacts);
The method is expecting an array, not an object.
Use the $in operator.
Template.contacts.events({
'submit #delete-contacts-form': function (e, template) {
// assumes permissions are set on server appropriately.
Contacts.remove({
_id: {
$in: $(e.target).find('input:checked').map(el => el.val()) // assumes the value of each checkbox is the _id
}
});
}
});
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.
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);
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}}
I'm looking through the Angular docs and I can't better documented stuff.
My problem is as follows:
I have a filter:
.filter('filteringService', function () {
return function (photos, categsList) {
if (photos !== undefined) {
var filteredPosts = [];
console.log('Categories or Selected Categories:');
console.log(categsList);
//DEVEL Only, assign a SEARCH value, can't pass the data from the list now.
categsList = 'people';
if (categsList === undefined) {
for(i=0; i < photos.length; i++) {
filteredPosts.push(photos[i]);
}
} else {
console.log('Trying to push a category slug to search for.');
//TASK: Convert in multiple possible selections.
filteredPosts = [];
}
console.log('Filter returns ' + filteredPosts.length + ' posts');
return filteredPosts;
}
};
});
And I have the template
<div class="photos">
<div class="filters">
<ul>
<li><a>ALL</a></li>
<li ng-repeat="category in categsList">
<a ng-checked="category[0]" ng-model="category[0]">{{ category[1] }}</a>
</li>
</ul>
</div>
<ul class="photos-list">
<li ng-repeat="photo in photos|filteringService:category">
<h1>{{ photo.title }} click LINK</h1>
<ul class="categories">
<li ng-repeat="category in photo.categories">
{{ category.title }}
</li>
</ul>
</li>
</ul>
</div>
There's a huge object with posts called photos and then there's a category list called categsList.
The photos object has the items from the categs list in it. I WANT to be able to filter with the CLICKED element through that list, and maybe multiple filter, but first to pass on the actual filter value to the filter service, I can't seem to do that.
How should I do that?
Apparently I managed to pass the filter value, in a dirty way (I GUESS), like this
<a ng-bind="category.slug" ng-click="returnFilter(category.slug);" ng-model="category.slug">{{ category.title }}</a>
it goes here
$scope.returnFilter = function(theSlug) {
$scope.filterBy = theSlug;
};
and it comes out here
<li ng-repeat="photo in photos|filteringService:filterBy">
It's working, but Is this correct?
EDIT: Also with this way in mind, I could pass an array as theSlug so I can do multiple filtering, and when clicking two times on the same item it would get it out of the array. hmmm
EDIT 2:
Let's say the resulting array is under 15 items, could do I run some action in the controller knowing this?
Actually the other way around, could I query from the controller the resulting array that the filter outputs?
I can't $watch the first array, I guess the filter creates a new array and puts those results in page. How could I watch the resulting array for changes and do stuff in the controller?