I have an Ember.js (1.0.0) Application for which I am trying to implement the built-in Ember.Select view.
This piece of the application shows three lists of tasks: inProgress, completed, and unassigned. The user can filter the tasks shown by their corresponding project. This is where the Ember.Select view comes in. However, when I load the route, Ember barks at me about the type of value I am giving it:
Assertion failed: The value that #each loops over must be an Array. You passed projects.all
Uncaught TypeError: Object projects.all has no method 'addArrayObserver'
Uncaught Error: Something you did caused a view to re-render after it rendered but before it was inserted into the DOM.
I have been wrestling with this for hours, trying different permutations of the code below - and I know I must be missing something obvious, because it just can't be this difficult to get such a simple component to work properly. Hoping you guys can point me in the right direction.
Here is my Route:
Bee.TasksIndexRoute = Bee.Auth.Route.extend
setupController: (ctrl) ->
# get tasks
Bee.Auth.send
url: Bee.endpoint "/tasks"
.done (tasks) ->
ctrl.set "tasks.all", tasks
# get projects
Bee.Auth.send
url: Bee.endpoint "/projects"
.done (projects) ->
ctrl.set "projects.owned", projects.owned
ctrl.set "projects.participating", projects.participating
ctrl.set "projects.all", projects.owned.concat projects.participating
Here is my Controller:
Bee.TasksIndexController = Ember.ObjectController.extend
project: null
content:
tasks:
all: []
inProgress: []
completed: []
unassgined: []
projects:
all: []
owned: []
participating: []
visible: (->
ctrl = #
# filter tasks here
).property "project"
Here is my Template:
<script type="text/x-handlebars" id="tasks/index">
<div class="center-pane">
<div class="top_options">
<div class="project_filter">
<strong>Viewing: </strong>
{{view Ember.Select
content=projects.all
optionValuePath='content._id'
optionLabelPath='content.title'
value=project
prompt='All Tasks'
}}
</div>
<strong class="gold-gradient option_button">
{{#link-to 'tasks.create' classNames='new_task'}}Create Task{{/link-to}}
</strong>
</div>
<div class="col3">
<div class="col-header in-progress light-gradient">
<h3>In Progress</h3>
</div>
<div id="tasks_active_list">
{{#if visible.inProgress.length}}
<ul>{{#each visible.inProgress}}{{view Bee.TaskListView}}{{/each}}</ul>
{{else}}
<p class="no_projects">None</p>
{{/if}}
</div>
</div>
<div class="col3">
<div class="col-header completed light-gradient">
<h3>Completed</h3>
</div>
<div id="tasks_closed_list">
{{#if visible.completed.length}}
<ul>{{#each visible.completed}}{{view Bee.TaskListView}}{{/each}}</ul>
{{else}}
<p class="no_projects">None</p>
{{/if}}
</div>
</div>
<div class="col3">
<div class="col-header unassigned light-gradient">
<h3>Unassigned</h3>
</div>
<div id="tasks_unassigned_list">
{{#if visible.unassigned.length}}
<ul>{{#each visible.unassigned}}{{view Bee.TaskListView}}{{/each}}</ul>
{{else}}
<p class="no_projects">None</p>
{{/if}}
</div>
</div>
</div>
</script>
Any insight will be much appreciated. I do know that the Ember.Select is the culprit, since when I replace it with a simple:
<select>
{{#each projects.all}}
<option value="{{_id}}">{{title}}</option>
{{/each}}
</select>
... it renders fine - however I need to use the Ember.Select so I can bind the value to the project property on the TasksIndexController - since I will use that as an observable for firing the visible function.
try setting projects.all to null up front. maybe ember select has an issue with the pojo default array on the class.
Bee.TasksIndexController = Ember.ObjectController.extend
project: null
content:
tasks:
all: []
inProgress: []
completed: []
unassgined: []
projects:
all: null
owned: []
participating: []
visible: (->
ctrl = #
# filter tasks here
).property "project"
setupController: (ctrl) ->
# get tasks
Bee.Auth.send
url: Bee.endpoint "/tasks"
.done (tasks) ->
ctrl.set "tasks.all", tasks
# get projects
Bee.Auth.send
url: Bee.endpoint "/projects"
.done (projects) ->
ctrl.set "projects.owned", projects.owned
ctrl.set "projects.participating", projects.participating
ctrl.set "projects.all", projects.owned.concat projects.participating
Here's a simplified example: http://emberjs.jsbin.com/aletIyU/3/edit
Related
I am new to Javascript and Meteor and having some trouble getting the Meteor autocomplete package from Mizzau to work correctly. I can get the form to autocomplete just fine, but having trouble getting it to filter my todos. The end result I am hoping for is to enter in a todo into the autocomplete and have it filter the subscription, I would also settle for search and going from there. I will also say my initial state is the list returns 0 todos (none are displayed) I feel like I may be close. A good part of my code came from this: Meteor - autocomplete with "distinct" feature?
T
Does it have something to do with my subscription?
Here is my server side publish call:
Meteor.publish("todosAuto", function(selector, options) {
Autocomplete.publishCursor(Todos.find(selector, options), this);
this.ready();
});
My client side subscription:
Meteor.subscribe('todosAuto');
The relevant part of my template:
<div class="container todoFormSec">
<div class="col-md-4">
{{> inputAutocomplete settings=settings id="msg" class="form-control" placeholder="Search..."}}
</div>
<div class="row">
<div class="col-md-5 pull-right">
<h1 class="todocountstyle text-right">You Have {{ todoCount }} Todos</h1>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="todos">
{{ #each todosAuto }}
{{ >todo }}
{{ /each }}
</div>
</div>
</div>
</div>
And my settings:
Template.home.helpers({
todos: function() {
return Todos.find();
},
todoCount: function() {
return Todos.find({userid: Meteor.userId()}).count();
},
settings: function() {
return {
position: "top",
limit: 5,
rules: [
{
token: '#',
collection: 'Todos',
field: "title",
subscription: 'todosAuto',
template: Template.titlePill
},
{
token: '#',
collection: 'Todos',
field: "categories",
options: '',
subscription: 'todosAuto',
matchAll: true,
template: Template.dataPiece
}
]
};
}
});
Template.home.events({ // listen for selection and subscribe
"autocompleteselect input": function(event, template, doc) {
Meteor.subscribe("todosAuto", doc.title);
}
});
In the past I tried to use this autocomplete package you are having trouble with. I found it just wasn't high fidelity enough for my needs. Therefore I recommend Twitter typeahead and bloodhound to you. I am very happy with the following packages ajduke:bootstrap-tokenfield in combination with sergeyt:typeahead
The time investment is well worth it. See my previous posting for examples. Here are more examples.
If the above is too complicated, try jeremy:selectize. Point is that there are plenty of better packages out there.
I have a template in wish I have 2 components that represents different Models. I need to create a model that contains both datas, for each component. If I have only one model everything works fine, but when I add other one, then this error happens in the console.
Error while processing route: events record is undefined ember$data$lib$system$store$finders$$_find/</<#http://localhost:1361/test/frontend/bower_components/ember-data/ember-data.prod.js:7475:11
Backburner.prototype.run#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:222:18
ember$data$lib$system$store$$Store<._adapterRun#http://localhost:1361/test/frontend/bower_components/ember-data/ember-data.prod.js:13133:16
ember$data$lib$system$store$finders$$_find/<#http://localhost:1361/test/frontend/bower_components/ember-data/ember-data.prod.js:7470:1
tryCatch#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:53070:14
invokeCallback#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:53085:15
publish#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:53053:9
#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:31253:7
Queue.prototype.invoke#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:901:9
Queue.prototype.flush#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:965:11
DeferredActionQueues.prototype.flush#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:765:11
Backburner.prototype.end#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:158:9
Backburner.prototype.run#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:226:13
run#http://localhost:1361/test/frontend/bower_components/ember/ember.prod.js:19151:12
ember$data$lib$adapters$rest$adapter$$RestAdapter<.ajax/</hash.success#http://localhost:1361/test/frontend/bower_components/ember-data/ember-data.prod.js:1728:15
n.Callbacks/j#http://localhost:1361/test/frontend/bower_components/jquery/dist/jquery.min.js:2:26920
n.Callbacks/k.fireWith#http://localhost:1361/test/frontend/bower_components/jquery/dist/jquery.min.js:2:27738
x#http://localhost:1361/test/frontend/bower_components/jquery/dist/jquery.min.js:4:11251
.send/b/<#http://localhost:1361/test/frontend/bower_components/jquery/dist/jquery.min.js:4:14765
The route of the template that contains the components is:
App.EventsRoute = Ember.Route.extend({
model: function()
{
return Ember.RSVP.hash({
event: this.store.find('event'),
featured: this.store.find('event', 'featured')
});
}
});
Here is my template:
<script type="text/x-handlebars" id="events">
<div class="col-xs-8 pull-left">
{{#each event as |event|}}
{{#event-box event=event}}{{/event-box}}
{{else}}
no events
{{/each}}
...
{{#each featured as |highlight|}}
{{#highlight-event hlevent=highlight}}
{{/highlight-event}}
{{else}}
No Highlights
{{/each}}
...
</script>
Does anyone knows why this error happens and what can I do to solve it?
this.store.find('event', 'featured') is invalid.
Also, find is deprecated.
With the latest Ember Data, you should use store.query().
You'd probably use it like
this.store.query('event', {featured: true})
or
this.store.query('event', {filter: 'featured'})
You'll need to adjust your adapter accordingly. Something like:
urlForQuery: function(query, modelName) {
if (query && query.featured === true) {
delete query.featured;
return this._buildURL(modelName, 'featured');
}
return this._super(query, modelName);
}
This should generate an URL like http://..../events/featured.
I'm trying to learn ember by following along with Vic Ramons Ember Rails tutorial.
I'm stuck trying to list the users I have fetched from Rails.
<!-- /templates/users.handlebars -->
<article id="users">
<h2>Users</h2>
<ul>
{{#each user in controller }}
<li>{{ user.email }}</li>
{{/each}}
</ul>
</article>
The /templates/users.handlebars is rendered but no users are listed.
I have checked the JSON output which is ok. When I check the ember inspector tab in chrome I can see 20 'user' models in the Data section.
What is the correct way to list the user records?
/routes/users.js:
Tagged.UsersRoute = Ember.Route.extend({
model: function(){ return this.store.findAll('user') }
});
/models/users.js:
Tagged.User = DS.Model.extend({
email: DS.attr('string')
});
/controllers/users.js:
Tagged.UsersController = Ember.Controller.extend({
});
/router.js:
Tagged.Router.map(function() {
this.resource('users', { path: '/users' })
});
adapters/application_adapter.js:
Tagged.ApplicationAdapter = DS.ActiveModelAdapter.extend({});
The controller JSON response:
{ "users":[
{"id":"5599bbc44d6178d3ae000000","email":"sasha#example.com"},
{"id":"5599bbc54d6178d3ae000001","email":"roberta#example.com"},
{"id":"5599bbc54d6178d3ae000002","email":"reyna.mayert#example.com"}
# ...
] }
<article id="users">
<h2>Users</h2>
<ul>
{{#each user in model }}
<li>{{ user.email }}</li>
{{/each}}
</ul>
</article>
In templates model property of controller is not usually used. If you change you /controllers/users.js to:
Tagged.UsersController = Ember.ArrayController.extend({
});
It should work. Because UsersController becomes a ArrayController which works with #each while normal controller does not.
I'm following a Meteor tutorial, following it step by step and I have run into two issues:
1) when I call the {{> message}} between {{#each messages}} and {{/each}}, my "check if it works" doesn't show up at all. When I call the {{> message}} anywhere else, my "check if it works" shows up!
{{messages}}
<template name="messages">
<h3>message list</h3>
{{#each messages}}
{{> message}} <!--echo of message template-->
{{/each}}
</template>
<template name="message">
<h4>check if it works</h4> <!--didn't show up on page-->
<p>{{name}}: {{message}}</p>
</template>
2) Also none of my Javascript works at all.
I type in 'Messages.insert({ name: 'Eunice', message: 'hello world', time: 10})' to the console. and it is supposed to have Eunice: hello world pop up, sorted by time.
Messages = new Meteor.Collection('messages');
if (Meteor.is_client){
Template.messages.messages = function () {
return Messages.find({}, { sort: {time: -1} });
};
}
I'm usually a good de-bugger, so I don't know where I made a mistake. So I probably misunderstood how something works going from console to collections to templates. Thanks!
Your if check is incorrect
if(Meteor.is_client) {
}
Should be
if(Meteor.isClient) {
}
im having a problem with my ember app. Im new to it, and trying to do something fun. So the idea of this app is to go and fetch a list of artists from a server via an ajax call, and then if you click the artist it will go to the server again and fetch the albums via another ajax call.
So the first part is working, it is actually fetching the artists through the ajax call when i click on "music library", but then when clicking on the artist it throws the following error:
Assertion failed: Error while loading route: TypeError: Object [object Object] has no method 'addArrayObserver'
I've read so many different options, and i think im on the right track because by printing on the console i can see that it is actually going to the server and fetching the right artist's albums, but the error is throw at the last moment, so it is not displaying the albums. I was also able to show the albums when reloading or typing the url (not now, since i changed the code to implement the afterModel)
So, here is my code:
App = Ember.Application.create({
LOG_TRANSITIONS: true,
LOG_TRANSITIONS_INTERNAL: true
});
App.Library = Ember.Object.extend({
name: null,
artist: []
});
App.Library.reopenClass({
loadArtist: function() {
var artistList = Em.A();
$.getJSON('url').then(function(data){
//json parsing, creating a library object and putting it into the array
});
return artistList;
}
});
App.Artist = Ember.Object.extend({
id: null,
name: null,
coverArt: null,
albumCount: null
});
App.Albums = Ember.Object.extend({
albums: []
});
App.Artist.reopenClass({
loadAlbums: function(params) {
var albumsJson = 'url' + params.artist_id +'';
var albumList = Em.A();
$.getJSON(albumsJson).then(function(data){
//parsing json, creating artist objects and pushing them into the array
});
return albumList;
//});
}
});
/*****************************ROUTER**************************************************************************************/
App.Router.map(function() {
// put your routes here
this.resource('library', function() {
this.resource('artist', { path: '/:artist_id'});
});
});
App.IndexRoute = Ember.Route.extend({
model: function() {
var hi = ['Welcome'];
return hi;
}
});
App.LibraryRoute = Ember.Route.extend({
model: function() {
return App.Library.loadArtist();
}
});
App.ArtistRoute = Ember.Route.extend({
model: function(params) {
this.transitionTo('artist', params);
},
afterModel: function(params, transition){
var artist = Em.A();
if(params.artist_id==null){
artist.push(App.Artist.create({artist_id: params.id}));
} else {
artist.push(App.Artist.create({artist_id: params.artist_id}));
}
return App.Artist.loadAlbums(artist[0]);
}
});
/**************************************CONTROLLERS***********************************************************************************/
App.ArtistController = Ember.ArrayController.extend({
needs: "library"
});
App.LibraryController = Ember.ArrayController.extend({});
I would really appreciate some help!
Also, the HTML is as follows:
<script type="text/x-handlebars">
<div class="navbar navbar-default">
<div class="navbar-inner">
<a class="navbar-brand" href="#">My Library</a>
<ul class="nav navbar-nav">
<li>{{#linkTo 'index'}}Home{{/linkTo}}</li>
<li>{{#linkTo 'library'}}Music Library{{/linkTo}}</li>
</ul>
</div>
</div>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
<div class="container">
{{#each item in model}}
<h1>{{item}}</h1>
{{/each}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="library">
<div class="container">
<div class="row">
<div class="col-md-4">
<table class="table">
{{#each model}}
<tr><td>
{{name}}
</td></tr>
{{#each artist}}
<tr><td>
{{#linkTo 'artist' this}}
{{name}}
{{/linkTo}}
<!--<a {{action 'selectArtist' this}}> {{name}} </a>-->
</td></tr>
{{/each}}
{{/each}}
</table>
</div>
<div class="col-md-8">
<p>Albumes</p>
{{outlet}}
</div>
</div>
</div>
</script>
<script type="text/x-handlebars" data-template-name="artist">
<div class="container">
<div class="col-md-4">
<table class="table">
<tr><td><p>{{controllers.library.artist.name}}</p></td></tr>
{{#each itemController='album'}}
<tr><td>
{{{name}}}
</td></tr>
{{/each}}
</table>
</div>
</div>
</script>
Thanks a lot!!
To get rid of the error you need to modify the model function of the App.ArtistRoute, to return an array as App.ArtistController is an Ember.ArrayController.
For example,
App.ArtistRoute = Ember.Route.extend({
model: function(params) {
//this.transitionTo('artist', params);
return [];
},
....
Or even place the code of afterModel function in model function to retrieve the albums of this artist.
Although i'm not certain if you really want the model of your artist context to be the albums, it does not look correct to me. I would suggest to make the App.ArtistController aν Ember.ObjectController, assign the model to an App.Artist object and store the albums related to this artist in a property of the App.Artist class. In that case you will need to add a property in App.Artist and create a class of App.Album.
With this in mind have a look at the following example which is a very rough modification of your code (caution the App.ArtistController has not been switched instead its model is an array of albums),
http://emberjs.jsbin.com/AdOfiyiN/2#/library/2
OK, i solved it using this question:
Why isn't my ember.js route model being called?
Instead of putting the logic in the model or afterModel, i just needed to set the controller.
Hope it helps to someone.
Best!