I'm new to Ember.js and I'm trying to get my head around it.
I have the following code (http://jsfiddle.net/6wPmW/ for a working example):
<script type="text/x-handlebars">
<div id="ViewAddresses" class="location_search_results selected_searches clearfix">
<div>
<div>
{{#each MapSearch.ViewAddressesC}}
<div class="row">ghfdg</div>
{{/each}}
</div>
</div>
</div>
</script>
JS:
MapSearch = Ember.Application.create();
MapSearch.ListAddress = Ember.Object.extend({
list_info: null,
node_level: null,
node_value: null,
removed_properties: null
});
MapSearch.ViewAddressListC = Ember.ArrayController.create({
content: [],
initialize: function() {
me = this;
var l = MapSearch.ListAddress.create({
node_level: "test",
node_value: "test"
});
me.pushObject(l);
var l = MapSearch.ListAddress.create({
node_level: "test",
node_value: "test"
});
me.pushObject(l);
console.log(me);
}
});
MapSearch.ViewAddressListC.initialize();
console.log(MapSearch.ViewAddressListC.get("content"));
Surely I should get two <divs> created from the each loop?
The error is in your template:
{{#each MapSearch.ViewAddressesC}}
should be
{{#each MapSearch.ViewAddressListC}}
See this JSFiddle.
Related
How to update hasMany in Ember.js using different controllers?
Hi
I have Ruby on Rails 4.0.3 app and I am using Ember.js
DEBUG: Ember : 1.6.0-beta.3 ember.js?body=1:3917
DEBUG: Ember Data : 1.0.0-beta.7+canary.f482da04 ember.js?body=1:3917
DEBUG: Handlebars : 1.3.0 ember.js?body=1:3917
DEBUG: jQuery : 1.11.0
I want to display hasMany in the same view using different controllers.
I have seen some example on StackOverflow but most (if not all) of them are for displaying records.
Ok talk is cheap, I am showing the code:
Models:
-javascripts/models/task.js
EmTasks.Task = DS.Model.extend({
name: DS.attr('string'),
description: DS.attr("string"),
list: DS.belongsTo('list')
});
-javascripts/models/list.js
EmTasks.List = DS.Model.extend({
name: DS.attr('string'),
tasks: DS.hasMany('task')
});
Router:
-javascripts/router.js
EmTasks.Router.map(function(){
return this.route("lists", {
path: '/'
});
});
EmTasks.ListsRoute = Ember.Route.extend({
model: function() {
return this.store.find('list');
}
});
Controllers:
-javascripts/controllers/lists_controller.js
EmTasks.ListsController = Em.ArrayController.extend({
addList: function() {
this.store.createRecord('list', {
name: this.get('newListName')
}).save();
return this.set('newListName', '');
},
destroyList: function(id) {
if (confirm("Are you sure?")) {
this.get('store').find('list', id).then( function(record) {
record.destroyRecord();
});
}
},
});
-javascripts/controllers/list_controller.js
EmTasks.ListController = Em.ObjectController.extend({
actions: {
editList: function() {
this.set('isEditingList', true);
var model = this.get('model')
},
acceptChanges: function () {
this.set('isEditingList', false);
var name = this.get('model.name');
if (Ember.isEmpty(name)) {
this.send('removeList');
} else {
var list = this.get('model')
list.set('name', name);
list.save()
}
},
removeList: function () {
var list = this.get('model');
list.destroyRecord();
}
},
isEditingList: false
});
-javascripts/controllers/task_controller.js
EmTasks.TaskController = Em.ObjectController.extend({
isEditingTask: false
});
Templates:
-javascripts/templates/lists.handlebars [fragment]
{{#each itemController='list'}}
<div class='col-md-8'>
<h3>
{{#if isEditingList}}
{{edit-input class="form-control" value=name focus-out="acceptChanges" insert-newline="acceptChanges"}}
{{else}}
<div {{action 'editList' on='doubleClick'}}>
{{name}}
</div>
{{/if}}
</h3>
</div>
<div class='col-md-4 down13p'>
<button class="btn btn-danger btn-small pull-right" {{action "destroyList" id}} type="button">
<span class="glyphicon glyphicon-ban-circle"></span>
</button>
</div>
{{#each task in this.tasks }}
<div class="col-md-10">
{{#if task.isEditingTask}}
{{edit-input class="form-control" value=task.name focus-out="acceptChanges" insert-newline="acceptChanges"}}
{{else}}
<div {{action 'editList' on='doubleClick'}}>
{{name}}
</div>
{{/if}}
But is looks like isEditingTask property is not working...
Any idea how to fix that?
OK found a solution, just add itemController to tasks each loop
{{#each task in this.tasks itemController='task' }}
<div class="col-md-10">
{{#if task.isEditingTask}}
{{edit-input class="form-control" value=task.name focus-out="acceptChanges" insert-newline="acceptChanges"}}
{{else}}
<div {{action 'editTask' on='doubleClick'}}>
{{name}}
</div>
{{/if}}
HTH
I have a backbone app where I want a view to be displayed when triggered. When i click the anchor the console says: Uncaught TypeError: Cannot read property 'fn' of undefined - I checked other issues of this kind and they say that jQuery is not loaded?? wtf? I dont get it...
My MenuView:
var LeftMenuView = Backbone.View.extend({
template: Handlebars.compile(Template),
events: {
'click li a.artAll': 'artAll',
},
artAll: function(event) {
event.preventDefault();
var artAllRouter = new Backbone.Router();
var route = '/artists/top100/all';
artAllRouter.navigate(route, {trigger: true});
}
....
The console tells me that the error is rooted in handlebars.js?
My HTML template:
<div>
{{#each}}
<p>
{{artist_name}}
</p>
{{/each}}
</div>
and my View:
define(['backbone','handlebars', 'text!templates/TopAllArtists.html'],
function(Backbone,Handlebars, Template) {
var TopAllArtView = Backbone.View.extend({
template: Handlebars.compile(Template),
initialize: function () {
_.bindAll(this, 'render');
},
render: function() {
var self = this;
self.collection.each(function(model){
self.$el.append(self.template({
artist_name:model.get('artist_name')
})
);
});
return this;
}
});
return TopAllArtView;
}
);
Anyone know what might be the issue?
According to the Handlebars documentation the each requires a list to iterate over,
<ul class="people_list">
{{#each people}}
<li>{{this}}</li>
{{/each}}
</ul>
Is artist name something to iterate over?
If model.get('artist_name') is iterable, ['name1', 'name2', ...] than,
<div>
{{#each artist_name}}
<p>
{{this}}
</p>
{{/each}}
</div>
If model.get('artist_name') is a string, 'Johann Sebastian Bach' than,
<div>
<p>
{{artist_name}}
</p>
</div>
I'm trying to write a pretty simple app: I have some games (say chess, tictactoe... whatever), and there are several boards of each game. I want to show a list of games, and then show a list of boards when you click on a game.
But I'm facing a lot of problems. I'll first describe them, and I'll paste the code after that:
The list of games is correctly shown. No problem here.
When I click a game, I get this error:
Uncaught Error: assertion failed: an Ember.CollectionView's content must implement Ember.Array. You passed <(generated game controller):ember237>
BUT if I press F5 or write the URL manually, everything works fine. And I have no idea why.
UPDATE: I've seen that if I change the games template, changing the {{#linkTo}} with a hand-written link, everything works OK:
This is the non-working linkTo: {{#linkTo 'game' game}}{{game.name}}{{/linkTo}}. It builds the URL correctly, but it fails when I click on it.
This is a hand-written <a> tag: {{game.name}}. It works perfectly.
The Url of each board should follow this format:
/games/1/boards/5
But when I write the {{#linkTo 'board' board}} what I get is:
/games/undefined/boards/5
Here is the code (You can see a "working" copy here in JBin. But it's not functional, because it relays on a local REST app):
The Router:
MGames.Router.map(function () {
this.resource('games', function () {
this.resource ('game', {path: '/:game_id'}, function () {
this.resource('board', {path: '/boards/:board_id'});
});
});
});
MGames.IndexRoute = Ember.Route.extend({
redirect: function () {
this.transitionTo('games');
}
});
MGames.GamesRoute = Ember.Route.extend ({
model: function() {
return MGames.Game.findAll();
}
});
MGames.GameRoute = Ember.Route.extend ({
model: function(params) {
return MGames.Board.findAllByGame(params.game_id);
}
});
MGames.BoardsRoute = Ember.Route.extend ({
model: function(params) {
return this.modelFor('game').then(
function (game) {
return MGames.Board.find(game.get('id'), params.board_id);
}
);
}
});
The models:
MGames.Game = Ember.Object.extend({
id: null,
name: null,
icon: null
});
MGames.Game.reopenClass({
findAll: function() {
var url = [MGames.GAMES_API_URL];
url.push ('games');
url = url.join('/');
var result = Ember.ArrayProxy.create({ content: [] });
$.getJSON(url).then (
function (response) {
response.forEach(function (child) {
result.pushObject (MGames.Game.create(child));
});
}
);
return result;
},
find: function (id) {
var url = [MGames.GAMES_API_URL];
url.push ('games');
url.push (id);
url = url.join('/');
var game = MGames.Game.create({ isLoaded: false });
$.getJSON(url).then (
function(response) {
game.setProperties(response);
game.set('isLoaded', true);
}
);
return game;
}
});
MGames.Board = Ember.Object.extend({
id: null,
name: null,
owner: null,
game: null,
is_public: null,
created_at: null
});
MGames.Board.reopenClass({
findAllByGame: function (game) {
var url = [MGames.GAMES_API_URL];
url.push ('games');
url.push (game);
url.push ('boards');
url = url.join('/');
var result = Ember.ArrayProxy.create({ content: [] });
$.getJSON(url).then (
function (response) {
console.log (response);
response.forEach(function (child) {
result.pushObject (MGames.Board.create(child));
});
}
);
return result;
},
find: function (game, board) {
url = [MGames.GAMES_API_URL];
url.push ('games');
url.push (game);
url.push ('boards');
url.push (board);
url = url.join('/');
var result = MGames.Board.create();
$.getJSON(url).then (
function(response) {
result.setProperties(response);
}
);
return result;
}
});
And the template:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>MGames</title>
<link rel="stylesheet" href="css/bootstrap.css">
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<script type="text/x-handlebars">
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<div class="nav-collapse collapse">
<ul class="nav">
<li class="active">{{#linkTo 'index' class="brand"}}MGames{{/linkTo}}</li>
</ul>
</div>
</div>
</div>
</div>
<div class="container">
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" id="games">
<div class="row">
<header id="header">
<h1>Games</h1>
</header>
<ul>
{{#each game in controller}}
<li>
{{#linkTo 'game' game}}{{game.name}}{{/linkTo}}
</li>
{{/each}}
</ul>
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" id="game">
<div class="row">
<div class="span3" id="boards">
<header id="header">
<h1>Boards</h1>
</header>
<ul id="board-list">
{{#each board in controller}}
<li>
{{#linkTo 'board' board}}{{board.name}}{{/linkTo}}
</li>
{{/each}}
</ul>
</div>
<div class="span9">
{{outlet}}
</div>
</div>
</script>
<script type="text/x-handlebars" id="board">
<header id="header">
<h1>{{game.name}} - {{name}} <small>{{owner.nickname}}</small></h1>
</header>
</script>
<script src="js/libs/jquery.js"></script>
<script src="js/libs/bootstrap.js"></script>
<script src="js/libs/handlebars.js"></script>
<script src="js/libs/ember.js"></script>
<script src="js/application.js"></script>
<script src="js/router.js"></script>
<script src="js/models/game.js"></script>
<script src="js/models/user.js"></script>
</body>
</html>
Ok, I finally figured out the problem. In my gameRoute I wrote this:
MGames.GameRoute = Ember.Route.extend ({
model: function(params) {
return MGames.Board.findAllByGame(params.game_id);
}
});
It worked when I write the URL directly in the browser bar, because Ember calls the model function, but when following a {{#linkTo}} the model is the one passed as parameter, so the modelfunction isn't called.
So the working code is this one (a little bit simplified):
MGames.GameRoute = Ember.Route.extend ({
model: function (params) {
// This is only called when loading the URL directly,
// not following a link. We load the game, and in the
// setupController we'll load the boards.
return MGames.Game.find(params.game_id);
},
setupController: function(controller, game) {
// This is *always* called, so we load the boards
model = MGames.Board.findAllByGame(game.id);
controller.set('model', model);
}
});
The board route that you are linking to has 2 dynamic segments, but you are providing only one. You need to change to,
{{#linkTo 'board' game board}}The board{{/linkTo}}
The undefined error is probably due to the ArrayController not getting a board as the corresponding game id is being passed as undefined. The above change should fix that too.
I'm creating an ember.js app. The first page is single field, with a button. On button click, I'd like it to go to the path #/deals/:api_key. However, when I click the button, I'm not clear on the best way to go about it.
Here's what i have so far:
App = Ember.Application.create();
App.Store = DS.Store.extend({
revision: 12,
adapter: 'DS.FixtureAdapter'
});
App.Deal = DS.Model.extend({
name: DS.attr('string')
});
App.Router.map(function() {
this.resource('start', { path: '/' });
this.resource('deals', { path: '/deals/:api_key' });
});
App.DealsRoute = Ember.Route.extend({
model: function(params) {
return App.Deal.find();
}
});
App.StartController = Ember.ObjectController.extend({
apiKey: "",
getDeals: function (model) {
this.transitionToRoute('deals');
}
});
App.DealsView = Ember.View.extend({
didInsertElement: function() {
// Add active class to first item
this.$().find('.item').first().addClass('active');
this.$().find('.carousel').carousel({interval: 1000});
}
});
<script type="text/x-handlebars" data-template-name="start">
{{view Em.TextField valueBinding="apiKey" placeholder="API Key"}}
<br />
<button {{action 'getDeals'}} class="btn btn-large">Get Won Deals!</button>
</script>
<script type="text/x-handlebars" data-template-name="deals">
<div id="carousel" class="carousel slide">
<div class="carousel-inner">
{{#each model}}
<div class="item">
{{name}}
</div>
{{/each}}
</div>
</div>
</script>
Any suggestions on the right way to pass data from a text input into the next transition as a query param?
you need to pass the parameter in the view in a linkTo helper, e.g.
{{#linkTo 'deals' api_key}}go to deals{{/linkTo}}
this generates a link with the dynamic section you need.
go to deals
check the docs about linkTo for more info: http://emberjs.com/guides/templates/links/
I have a simple example with Handlebars, and I cannot get it to work! Please help. I am trying to get the google app engine guestbook to work with handlebars instead of jinja2
HTML/Template code is as follows:
Hello {{user.nickname}}
<h2>Top 10 Most Recent Guestbook Entries</h2>
{{#each greetings}}
<br>
<small>[<i>{{date.ctime}}</i>]</small>
<b>
{{#if author}}
<code>{{author.nickname}}</code>
{{else}}
<i>anonymous</i>
{{/if}}
</b>
wrote:
{{comment}}
{{/each}}
</script>
<div id="comment_content"> </div>
<form id="comments" action="">
<div><textarea id="comment" name="content" rows="3" cols="60"></textarea></div>
<div><input id="comment_button" type="button" value="submit"></div>
</form>
{{ url_linktext }}
and here is the JS code:
<script>
$(document).ready(function() {
var source = $("#entry-template");
var srcHTML =source.html();
var template = Handlebars.compile(srcHTML);
// put all your jQuery goodness in here.
$("#comment_button").click(function(event) {
var data = JSON.stringify({
"login": "/_ah/login?continue=http%3A//localhost%3A8080/show",
"logout": "/_ah/login?continue=http%3A//localhost%3A8080/show&action=Logout",
"user": {
"nickname": "dummy",
"email": "dummy#me.com"
},
"greetings": [
{
"comment": "COMMENT1",
"date": {
"ctime": "Sun Feb 10 23:20:21 2013"
},
"author": {
"nickname": "dummy",
"email": "dummy#me.com"
}
}
]
})
var html = template(data);
console.log(html);
$("#comment_content").html(html);
});
});
</script>
Here is how I am referencing Handlebar source
Can someone please help?
Thanks a mil
Your big problem is that you're using JSON.stringify to prepare your data for the compiled template function:
var data = JSON.stringify({ ... });
var html = template(data);
That will end up handing the template function a string (which is a JSON representation of the data you want) when it wants just the object. Drop the JSON.stringify and things will start behaving better:
var data = { ... };
var html = template(data);
Demo: http://jsfiddle.net/ambiguous/Axmbd/
Also, this part of your HTML:
{{ url_linktext }}
doesn't appear to be inside the template's <script> so the {{url}} and {{url_linktext}} won't be filled in. You can fix that by moving that <a> to the right place.