Routing and button click not working in Backbone + handlebars - javascript

index.html
<html>
<head>
<meta charset="utf-8" />
<meta name="format-detection" content="telephone=no" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="js/lib/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="js/lib/bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
<link href="js/lib/ratchet/ratchet-theme-ios.css" rel="stylesheet">
<link href="js/lib/ratchet/ratchet.css" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="css/index.css" />
<title>totter</title>
</head>
<body>
<div class="content">
</div>
<script src="js/lib/jquery-1.9.1.min.js"></script>
<script src="js/lib/underscore-min.js"></script>
<script src="js/lib/backbone-min.js"></script>
<script src="js/lib/bootstrap/js/bootstrap.js"></script>
<script src="js/lib/handlebars/handlebars-v1.3.0.js"></script>
<script src="js/lib/ratchet/ratchet.js"></script>
<script src="js/common/helper.js"></script>
<script src="js/app.js"></script>
<script src="js/views/home.js"></script>
<script src="js/views/signin.js"></script>
<script src="js/models/home.js"></script>
<script src="js/models/signin.js"></script>
</body>
</html>
app.js
var app = {
views: {},
models: {},
loadTemplates: function(views, callback) {
var deferreds = [];
$.each(views, function(index, view) {
if (app[view]) {
deferreds.push($.get('template/' + view + '.hbs', function(data) {
app[view].prototype.template = _.template(data);
}, 'html'));
} else {
alert(view + " not found");
}
});
$.when.apply(null, deferreds).done(callback);
}
};
app.Router = Backbone.Router.extend({
routes: {
"": "home",
"signIn":"SignIn"
},
home: function () {
// Since the home view never changes, we instantiate it and render it only once
if (!app.home) {
app.home = new app.HomeView();
app.home.render();
} else {
// delegate events when the view is recycled
app.home.delegateEvents();
}
},
SignIn:function(){
if (!app.signin) {
app.signin = new app.SignInView();
app.signIn.render();
} else {
// delegate events when the view is recycled
app.signin.delegateEvents();
}
}
});
$(document).on("ready", function () {
app.loadTemplates(["HomeView"],
function () {
app.router = new app.Router();
Backbone.history.start();
});
});
home.js
app.HomeView = Backbone.View.extend({
//Calling the render method to render view from the template
initialize:function(){
this.render();
},
//Pass the handlebars template for complilation and
render: function () {
var path = './template/HomeView.hbs';
Helper.GET_TEMPLATE(path, function(template) {
//pass collection to template to set values
var html = template(app.homeCollection.toJSON());
//pass collection to template to set values
$('.content').html(html);
});
$('.signin').bind('click', function(e) {
app.Router.navigate("signIn", {trigger: true});
});
}
});
app.home = new app.HomeView();
sigin.js
app.SigInView = Backbone.View.extend({
//Calling the render method to render view from the template
initialize:function(){
this.render();
},
//Pass the handlebars template for complilation and
render: function () {
var path = './template/SignInView.hbs';
Helper.GET_TEMPLATE(path, function(template) {
//pass collection to template to set values
var html = template(app.signinCollection.toJSON());
//pass collection to template to set values
$('.content').html(html);
});
}
});
app.signin = new app.SigInView();
helper.js
var Helper = {};
Helper.GET_TEMPLATE = function(path,callback){
var source, template;
$.ajax({
url: path,
success: function(data) {
source = data;
//Compile the raw data we got from the file
template = Handlebars.compile(source);
//execute the callback if passed
if (callback){
callback(template);
}
}
});
}
homeModel.js
var HomeModel = Backbone.Model.extend();
var homeData = new HomeModel({
id: 1,
signUpTitle: 'Sign Up for TOT ',
signInTitle: 'Sign In',
slogan:'slogan slogan slogan slogan slogan slogan slogan slogan slogan slogan '
});
/**
* Defining a Collection to set model
*/
var HomeCollection = Backbone.Collection.extend({
model: HomeModel
});
/**
* Defining a array to hold the collection
*/
app.homeCollection = new HomeCollection([homeData]);
HomeView.hbs
<header class="bar bar-nav">
<h1 class="title">totter</h1>
</header>
<div class="logo">
<img src = "img/choice.png">
</div>
{{#each []}}
<div class="textcontent">
<label>{{this.slogan}}</label>
</div>
<div class="footer">
<button class="btn btn-primary btn-block signup" style="">{{this.signUpTitle}}</button>
</div>
<div class="footer">
<button class="btn btn-primary btn-block signin">{{this.signInTitle}}</button>
</div>
{{/each}}
In the above code I used to develop a simple app with 2 views. I want to show sign-in view on button click of sign-in.
How can I achive this? I am using "handlebars" and "backbone.js".

The events aren't firing because you're utilizing the View el property. Either give it a preexisting element or insert the el itself to the DOM.
see the answer on the following discussion for a more comprehensive explanation.

Related

How to use external object in react?

A third party sent me this script. Basically,
include a script
call the object
onAuthorize will feedback data, then do something with data
Is it a way to integrate it with react? I think I need the data from onAuthorize to update my react state
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<title>Payment Gateway Test Page</title>
<script src="https://service.com/widget.js">
</script>
<style type="text/css">
iframe{border: 0;height: 50px;}
</style>
</head>
<body>
<div>
* Demo for widget
</div>
<br/>
<script>
// widget
mywidget.Button.render({
Client: {
id: "1234",
name: "testme"
},
payment: function (actions) {
var amountValue = parseFloat(document.getElementById("inp-amount").innerText);
return actions.createQuote(amountValue)
},
onAuthorize: function (data) {
// err
if (data.errorCode) {
this.onError(data);
return;
}
// money we need to pay
var amountValue = parseFloat(document.getElementById("inp-amount").innerText);
// we have such points, converted to money
var pointsDollars = parseFloat(data.pointsBurned * 0.005, 10);
// points to convert
document.getElementById('qp').innerText = data.pointsBurned;
// origPay - new_money = pay_now
document.getElementById('bal').innerText = '$' + (amountValue - pointsDollars);
},
onError: function (data) {
console.log(data);
},
onClicked: function (data) {
// on click
console.log(data);
}
}, "#container"); // container
</script>
<div id="container"></div>
<br/>
<div id="amount">
Checkout: $<span id="inp-amount">1543</span> <br>
Points to redeem: <span id="qp"></span> <br>
<hr>
Balance to pay: <span id="bal"></span> <br>
</div>
</body>
</html>
You could create an event and listen for that event. In onAuthorize you can trigger the event and pass the data.
Add an event in your page (not necessarily in React)
// Create the event
var event = new CustomEvent("authroize-me", { "detail": "some event info" });
React component
constructor() {
super();
this.handleAuthroizeMe = this.handleAuthroizeMe.bind(this);
}
handleAuthroizeMe(data) {
console.log(data);
}
componentDidMount() {
document.addEventListener('authroize-me', this.handleAuthroizeMe);
}
componentWillUnmount() {
document.removeEventListener("authroize-me", this.handleAuthroizeMe);
}
In onAuthorize
onAuthorize: function (data) {
// Dispatch event
document.dispatchEvent(event, data);
}
Another quick and dirty fix.
Expose a function from react component outside the react scope.
window.setAuthorizeState = (data)=> {
this.setState({authorizeState: data});
}
Call setAuthorizeState from onAuthorize
The code can be embedded in a component which renders the container. And in componentDidMount, the script can be placed.
class Widget extends Component {
componentDidMount() {
// script here
}
render() {
return (
<div id="container" />
);
}
}

How to create an array of previously retrieved posts from an AJAX request

Here is the problem I am working on.
Attached is an index.html.
Implement the next and previous buttons to navigate to next/previous posts from the API provider (https://jsonplaceholder.typicode.com).
Create a new tag that displays the current post ID.
Bonus points: Create a new array to store all of the previously retrieved posts, and display them in a list.
The API is from jsonplaceholder.typicode.com, so you don't need to implement that. A jsfiddle would be immensely appreciated.
<!DOCTYPE html>
<html>
<head>
<title>Vue Test</title>
<link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet' type='text/css' />
<div id="app">
<h1>{{ message }}</h1>
<div>
<span>{{post.title}}</span>
</div>
<button v-on:click="previousPost">Previous Post</button> <!-- // new vue directive - v-on:click, also -->
<button v-on:click="nextPost">Next Post</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.js"></script>
<script
src="https://code.jquery.com/jquery-3.1.1.min.js"
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
***emphasized text***crossorigin="anonymous"></script>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Welcome to Vue!',
post: {},
page: 1
},
mounted: function() {
this.getPost()
},
methods: {
nextPost: function() {
this.page = this.page + 1
this.getPost()
// Implement me
},
previousPost: function() {
// Implement me
this.page = this.page - 1
this.getPost()
},
getPost: function() {
var root = 'https://jsonplaceholder.typicode.com';
$.ajax({
url: root + '/posts/' + this.page,
method: 'GET'
})
.then((data) => {
console.log(data);
this.post = data;
});
}
}
})
</script>
<style>
/* Add any additional styles here */
body {
padding: 20px;
}
div {
margin: 12px 0;
}
</style>
I would also like to know what is meant by the post id over there. I have completed one task which shows the next and previous posts, but the other two tasks I am a little confused.

TypeError: Cannot read property 'getTime' of undefined

I am getting a problem when trying to use DayPilot Calendar in angularjs.
https://code.daypilot.org/63034/angularjs-event-calendar-open-source
When I downloaded sources and use it it was not working and throwing error
angular.js:9563 TypeError: Cannot read property 'getTime' of undefined
at loadEvents (daypilot-all.min.js:11)
at update (daypilot-all.min.js:11)
at Object.fn (daypilot-all.min.js:11)
at h.$digest (angular.js:12031)
at h.$apply (angular.js:12279)
at g (angular.js:7991)
at C (angular.js:8196)
at XMLHttpRequest.y.onreadystatechange (angular.js:8137)
Source code of the downloaded code is
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>DayPilot: AngularJS Event Calendar</title>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>
<script src="js/daypilot/daypilot-all.min.js" type="text/javascript"></script>
<!-- helper libraries -->
<script src="js/jquery/jquery-1.9.1.min.js" type="text/javascript"></script>
<!-- daypilot libraries -->
<script src="js/daypilot/daypilot-all.min.js" type="text/javascript"></script>
<link type="text/css" rel="stylesheet" href="media/layout.css" />
</head>
<body>
<div id="header">
<div class="bg-help">
<div class="inBox">
<hr class="hidden" />
</div>
</div>
</div>
<div class="shadow"></div>
<div class="hideSkipLink">
</div>
<div class="main">
<div ng-app="main" ng-controller="DemoCtrl" >
<div style="float:left; width: 160px">
<daypilot-navigator id="navi" daypilot-config="navigatorConfig" ></daypilot-navigator>
</div>
<div style="margin-left: 160px">
<div class="space">
<button ng-click="showDay()">Day</button>
<button ng-click="showWeek()">Week</button>
</div>
<daypilot-calendar id="day" daypilot-config="dayConfig" daypilot-events="events" ></daypilot-calendar>
<daypilot-calendar id="week" daypilot-config="weekConfig" daypilot-events="events" ></daypilot-calendar>
</div>
</div>
<script>
var app = angular.module('main', ['daypilot']).controller('DemoCtrl', function($scope, $timeout, $http) {
$scope.events = [];
$scope.navigatorConfig = {
selectMode: "day",
showMonths: 3,
skipMonths: 3,
onTimeRangeSelected: function(args) {
$scope.weekConfig.startDate = args.day;
$scope.dayConfig.startDate = args.day;
loadEvents();
}
};
$scope.dayConfig = {
viewType: "Day",
onTimeRangeSelected: function(args) {
var params = {
start: args.start.toString(),
end: args.end.toString(),
text: "New event"
};
$http.post("backend_create.php", params).success(function(data) {
$scope.events.push({
start: args.start,
end: args.end,
text: "New event",
id: data.id
});
});
},
onEventMove: function(args) {
var params = {
id: args.e.id(),
newStart: args.newStart.toString(),
newEnd: args.newEnd.toString()
};
$http.post("backend_move.php", params);
},
onEventResize: function(args) {
var params = {
id: args.e.id(),
newStart: args.newStart.toString(),
newEnd: args.newEnd.toString()
};
$http.post("backend_move.php", params);
},
onEventClick: function(args) {
var modal = new DayPilot.Modal({
onClosed: function(args) {
if (args.result) { // args.result is empty when modal is closed without submitting
loadEvents();
}
}
});
modal.showUrl("edit.php?id=" + args.e.id());
}
};
$scope.weekConfig = {
visible: false,
viewType: "Week",
onTimeRangeSelected: function(args) {
var params = {
start: args.start.toString(),
end: args.end.toString(),
text: "New event"
};
$http.post("backend_create.php", params).success(function(data) {
$scope.events.push({
start: args.start,
end: args.end,
text: "New event",
id: data.id
});
});
},
onEventMove: function(args) {
var params = {
id: args.e.id(),
newStart: args.newStart.toString(),
newEnd: args.newEnd.toString()
};
$http.post("backend_move.php", params);
},
onEventResize: function(args) {
var params = {
id: args.e.id(),
newStart: args.newStart.toString(),
newEnd: args.newEnd.toString()
};
$http.post("backend_move.php", params);
},
onEventClick: function(args) {
var modal = new DayPilot.Modal({
onClosed: function(args) {
if (args.result) { // args.result is empty when modal is closed without submitting
loadEvents();
}
}
});
modal.showUrl("edit.php?id=" + args.e.id());
}
};
$scope.showDay = function() {
$scope.dayConfig.visible = true;
$scope.weekConfig.visible = false;
$scope.navigatorConfig.selectMode = "day";
};
$scope.showWeek = function() {
$scope.dayConfig.visible = false;
$scope.weekConfig.visible = true;
$scope.navigatorConfig.selectMode = "week";
};
loadEvents();
function loadEvents() {
// using $timeout to make sure all changes are applied before reading visibleStart() and visibleEnd()
$timeout(function() {
var params = {
start: $scope.week.visibleStart().toString(),
end: $scope.week.visibleEnd().toString()
}
$http.post("backend_events.php", params).success(function(data) {
$scope.events = data;
});
});
}
});
</script>
</div>
<div class="clear">
</div>
</body>
</html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>
i am still confused why this problem is occurring again and again
You should check the response returned by "backend_events.php". DayPilot expects an array of events in JSON format. If there is any server-side error in the script the response will return an error message instead.
Most likely, there is a problem with permissions on the server side - the PHP script needs read/write permissions for daypilot.sqlite file which is in the application root.

backbone.js Can't find error in script

I'm new to javascript and backbone.js
I want to create simple web page with 10 squares with form that will take square id and color.
So every square must have its own style in CSS.
I tried to make it with 10 templates. But script doesn't work at all.
Here is my code:
alert("script entry");
$(function () {
blocks = [
{number: "1", state: "block1" },
{number: "2", state: "block2" },
{number: "3", state: "block3" },
{number: "4", state: "block4" },
{number: "5", state: "block5" },
{number: "6", state: "block6" },
{number: "7", state: "block7" },
{number: "8", state: "block8" },
{number: "9", state: "block9" },
{number: "10", state: "block10" },
];
var BlockModel = Backbone.Model.extend({
defaults:{
"state": "block1",
"number": "1"
}
});
var BlockCollection = Backbone.Collection.extend({
model: BlockModel,
});
var blockNumbers = new BlockCollection([
model:BlockModel
]);
var BlockView = Backbone.View.extend({
tagName: "blockTag",
className: "blockClass",
templates: {
"block1": _.template($('#block1').html()),
"block2": _.template($('#block2').html()),
"block3": _.template($('#block3').html()),
"block4": _.template($('#block4').html()),
"block5": _.template($('#block5').html()),
"block6": _.template($('#block6').html()),
"block7": _.template($('#block7').html()),
"block8": _.template($('#block8').html()),
"block9": _.template($('#block9').html()),
"block10": _.template($('#block10').html())
},
render: function () {
var state= this.model.get("state");
var tmpl = this.templates(state);
$(this.el).html(tmpl(this.model.toJSON()));
return this;
}
});
var appView = Backbone.View.extend({
el: $("#block"), //большой контейнер
initialize: function(){
this.collection = new blockNumbers(blocks);
this.render();
},
render: function(){
_.each(this.collection.models, function () {
that.renderBlock(this.model);
}, this);
},
renderBlock: function (inputModel) {
var blockView = new BlockView({
{model: inputModel}
});
this.$el.append(blockView.render().el);
}
});
var app = new appView();
});
Where is my error?
My index.html :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TEST</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="block">
<script type="text/template" id="block1">
<div class="block1"><%=number%></div>
<div class="buttonplace">
<input type="button" value="check" />
</div>
</script>
<script type="text/template" id="block2">
<div class="block2"><%=number%></div>
</script>
<script type="text/template" id="block3">
<div class="block3">3</div>
</script>
<script type="text/template" id="block4">
<div class="block4">4</div>
</script>
<script type="text/template" id="block5">
<div class="block5">5</div>
</script>
<script type="text/template" id="block6">
<div class="block6">6</div>
</script>
<script type="text/template" id="block7">
<div class="block7">7</div>
</script>
<script type="text/template" id="block8">
<div class="block8">8</div>
</script>
<script type="text/template" id="block9">
<div class="block9">9</div>
</script>
<script type="text/template" id="block10">
<div class="block10">10</div>
</script>
</div>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="underscore.js"></script>
<script type="text/javascript" src="backbone.js"></script>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
There are several problems with your code, primarily you are using parentheses in some cases instead of brackets [ and instead of curly braces {. You also have some extra trailing commas. Further in your HTML your closing tag for the block div should be before all your script templates.
For example
var blockNumbers = new BlockCollection([
model:BlockModel
]);
Should be
var blockNumbers = new BlockCollection({
model:BlockModel
});
And
var tmpl = this.templates(state);
Should be
var tmpl = this.templates[state];
In addition in your appView you are trying to instantiate a new instance of your instance
this.collection = new blockNumbers(blocks);
While you probably meant to do
this.collection = new BlockNumbers(blocks);
Here's a working jsBin
Aside from all that you have a lot of repetition with your templates, you can really consolidate them all into one or two templates.
For example you can just have one template for blocks with a button and one for blocks without a button and update the blocks state accordingly
<script type="text/template" id="blockWithButton">
<div class="block<%=number%>"><%=number%></div>
<div class="buttonplace">
<input type="button" value="check" />
</div>
</script>
<script type="text/template" id="blockWithoutButton">
<div class="block<%=number%>"><%=number%></div>
</script>
Another jsbin
templates: {
"block1": _.template($('#block1').html()),
...
"block10": _.template($('#block10').html())
},
you have defined an object above.
var tmpl = this.templates(state);
but you call it as a function.
you may get the templates as this.templates[state];
UPDATE
I think you can just use the same template as:
<script type="text/template" id="block">
<div class="block<%=number%>"><%=number%></div>
<div class="buttonplace">
<input type="button" value="check" />
</div>
</script>
and you can simplfy your model like this, too.
Of course, if you need.
UPDATE
You may new a Collection with some options out of single {} but not [] or more {}s, like this:
var blockNumbers = new BlockCollection({
model:BlockModel
});
...
var blockView = new BlockView({
model: inputModel
});
not:
var blockNumbers = new BlockCollection([
model:BlockModel
]);
...
var blockView = new BlockView({
{model: inputModel}
});
UPDATE
the blockNumbers is an instance of Collection, you can't fetch data for it by new like:
this.collection = new blockNumbers(blocks);
You should assign the bolckNumbers to this.collection, and give it an url , then call sync() or fetch() to get the data, then render it.
END
Lastly, I have found too much mistake of basics above, Backbone.js is simple but hard, you ought to be able to solve it yourself, it is useful to you.
Thanks.

Loading a single model with Ember.js

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.

Categories

Resources