The following code worked fine with RC4 but it doesn't work with RC6. index.html#/users/1/edit doesn't fill the form to edit the user entry. Can anybody tell me what I have to change to get this working with the new router?
app.js
App = Ember.Application.create();
App.Router.map(function() {
this.resource('users', function() {
this.resource('user', { path: ':user_id' }, function() {
this.route('edit');
});
})
});
App.UsersRoute = Ember.Route.extend({
model: function() {
return App.User.find();
}
});
App.UserController = Ember.ObjectController.extend();
App.UserEditRoute = Ember.Route.extend({
model: function() {
return this.modelFor("user")
},
renderTemplate: function() {
this.render({ into: 'users' });
},
setupController: function(controller, model) {
if (model.get('isNew') == false) {
var map = this.map || Ember.Map.create();
this.map = map;
var transaction = this.get('store').transaction();
if (map.get(model)) {
transaction = map.get(model);
} else {
map.set(model, transaction);
transaction.add(model);
}
}
},
events: {
commitThis: function(model) {
var map = this.map;
var transaction = map.get(model);
transaction.commit();
map.remove(model);
App.Router.router.transitionTo('users.index')
},
rollbackThis: function(model) {
var map = this.map;
var transaction = map.get(model);
transaction.rollback();
transaction.add(model);
App.Router.router.transitionTo('users.index')
}
}
});
App.UserEditController = Ember.ObjectController.extend({
save: function(model) {
this.send('commitThis', model)
},
undo: function(model) {
this.send('rollbackThis', model)
}
});
App.Store = DS.Store.extend({
adapter: 'DS.FixtureAdapter'
});
App.User = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string')
});
App.User.FIXTURES = [{
id: 1,
firstName: "Yehuda",
lastName: "Katz"
}, {
id: 2,
firstName: "Tom",
lastName: "Dale"
}]
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Userlist Demo</title>
<link href="css/bootstrap.css" rel="stylesheet">
<style>
body {
padding-top: 60px;
}
</style>
<link href="css/bootstrap-responsive.css" rel="stylesheet">
</head>
<body>
<script type="text/x-handlebars">
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="#">Demo</a>
<div class="nav">
<ul class="nav">
<li>{{#linkTo 'users'}}Users{{/linkTo}}</li>
</ul>
</div>
</div>
</div>
</div>
<div class="container">
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="index">
<h2>Demo Ember.js Application</h2>
<p>
A list of all users can be found {{#linkTo 'users'}}here{{/linkTo}}.
</p>
</script>
<script type="text/x-handlebars" data-template-name="users">
<div class='row'>
<div class='span7'>
<table class='table table-striped'>
<thead>
<tr>
<th>First name</th>
<th>Last name <i class="icon-arrow-down"></i></th>
<th></th>
</tr>
</thead>
<tbody>
{{#each this itemController="user"}}
<tr {{bindAttr class="isDirty:warning"}}>
<td>{{firstName}}</td>
<td>{{lastName}}</td>
<td>
{{#unless isNew}}
{{#linkTo 'user.edit' this activeClass="disabled" classNames="btn btn-small"}}<i class="icon-edit"></i> Edit{{/linkTo}}
{{/unless}}
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
<div class='span5'>
{{outlet}}
</div>
</div>
</script>
<script type="text/x-handlebars" data-template-name="user/edit">
<h2>Edit</h2>
<p><strong>First name</strong><br>{{input value=firstName type=text tabindex=1}}</p>
<p><strong>Last name</strong><br>{{input value=lastName type=text tabindex=2}}</p>
<p>
<button {{action 'save' this}} {{bindAttr class=":btn :btn-small :btn-primary content.isDirty:enabled:disabled"}} tabindex=4>Save changes</button>
<button {{action 'undo' this}} {{bindAttr class=":btn :btn-small content.isDirty:enabled:disabled"}} tabindex=5>Undo changes</button>
</p>
</script>
<script src="js/libs/jquery-1.9.1.js"></script>
<script src="js/libs/handlebars.js"></script>
<script src="js/libs/ember.js"></script>
<script src="js/libs/ember-data.js"></script>
<script src="js/libs/md5.js"></script>
<script src="js/app.js"></script>
</body>
</html>
Pretty sure this is because App.UserEditRoute.setupController is not calling _super. Strange cause I thought that breaking change was back in RC4. Anyway, try this:
App.UserEditRoute = Ember.Route.extend({
// ...
setupController: function(controller, model) {
this._super(controller, model);
// ...
}
}
Possibly related: Seems like setupController is saving state (this.map) on the route object. Surprised it works at all, for sure has potential to cause problems. Instead setupController should set properties on the local controller or model arguments, or use this.controllerFor() to access another controller.
In this case seems like a lot of code is not necessary, could just save/rollback on the model itself. So to simplify:
App = Ember.Application.create();
App.Router.map(function() {
this.resource('users', function() {
this.resource('user', { path: ':user_id' }, function() {
this.route('edit');
});
})
});
App.UsersRoute = Ember.Route.extend({
model: function() {
return App.User.find();
}
});
App.UserController = Ember.ObjectController.extend();
App.UserEditRoute = Ember.Route.extend({
model: function() {
return this.modelFor("user")
},
renderTemplate: function() {
this.render({ into: 'users' });
},
events: {
save: function(model) {
model.save().then( function() {
App.Router.router.transitionTo('users.index')
}, function() {
alert('save failed!');
});
},
undo: function(model) {
model.rollback();
App.Router.router.transitionTo('users.index')
}
}
});
App.Store = DS.Store.extend({
adapter: 'DS.FixtureAdapter'
});
App.User = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string')
});
App.User.FIXTURES = [{
id: 1,
firstName: "Yehuda",
lastName: "Katz"
}, {
id: 2,
firstName: "Tom",
lastName: "Dale"
}]
See working example here: http://jsbin.com/ixucos/2/edit
Related
I'm building an app that has the following code:
Routes:
App.Router.map(function() {
this.resource('gradebooks', function() {
this.resource('gradebook', { path: ':gradebook_id' });
});
});
App.IndexRoute = Em.Route.extend({
redirect: function() {
this.transitionTo('gradebooks');
}
})
App.GradebooksRoute = Em.Route.extend({
setupController: function(controller, model) {
Em.$.getJSON('/data/gradebooks/get', function(data) {
controller.set('model', data);
});
}
});
App.GradebookRoute = Em.Route.extend({
model: function(params) {
var id = params.gradebook_id;
return Em.$.getJSON('/data/gradebooks/get/' + id);
}
})
Controllers:
App.GradebooksController = Em.ArrayController.extend({
isActive: false,
actions: {
createGradebook: function(newTitle) {
var self = this;
if(newTitle.trim()) {
Em.$.get('/data/gradebooks/add/' + newTitle, {}, function(json) {
Em.$('#create-gradebook-modal').modal('hide').find('input').val('');
self.transitionToRoute('gradebook', json.id);
}, 'json');
}
}
}
});
Templates (gradebooks.hbs):
<div class="sidebar">
<div class="btn-container">
<button class="btn btn-block btn-info" data-toggle="modal" data-target="#create-gradebook-modal">
<i class="fa fa-book"></i>
Create Gradebook
</button>
</div>
<ul>
{{#each}}
<li {{bind-attr class="isActive:active"}}>
{{#link-to "gradebook" _id}}
{{title}}
{{/link-to}}
</li>
{{/each}}
</ul>
</div>
<div class="content">
<div class="container-fluid">
{{outlet}}
</div>
</div>
Templates (gradebook.hbs):
<h1>{{title}} <small>{{_id}}</small></h1>
<div class="btn-container">
<button class="btn btn-default"><i class="fa fa-pencil"></i> Rename</button>
<button class="btn btn-danger"><i class="fa fa-trash-o"></i> Trash</button>
</div>
What I'm having trouble with is under the GradebooksController.actions.createGradebook, I send a request to create the model and then I transition to the gradebook I just created. The creation and transition works just fine, but I want the sidebar (gradebooks.hbs) to show the newly created gradebook.
I think it has something to do with updating the model in the GradebooksRoute. How can I make it fetch for the models from the server again after creating a gradebook.
To elaborate on #fanta's comment, you'll want to do something like this:
App.GradebooksController = Em.ArrayController.extend({
isActive: false,
actions: {
createGradebook: function(newTitle) {
var self = this;
if(newTitle.trim()) {
var gradebook = Em.$.getJSON('/data/gradebooks/add/' + newTitle, {}, function(json) {
Em.$('#create-gradebook-modal').modal('hide').find('input').val('');
self.transitionToRoute('gradebook', json.id);
}, 'json');
self.get('content').pushObject(gradebook);
}
}
}
});
I will try to bind model,controller and template in ember
Here is my js
App = Ember.Application.create({});
App.Person = Ember.Object.extend({
firstName: "r",
lastName: "issa"
});
App.TestingRoute = Ember.Route.extend({
model: function () {
return App.Person.create();
},
setupController: function (controller, model) {
controller.set("model", model);
}
});
App.TestingController = Ember.ObjectController.extend({
submitAction: function () {
alert("My model is :" + this.get("model"));
}
});
my template is :
<script type="text/x-handlebars" data-template-name="application">
{{render testing}}
</script>
<script type="text/x-handlebars" data-template-name="testing">
{{input valueBinding="model.firstName"}}
{{input valueBinding="model.lastName"}}
<button {{action submitAction target="controller"}} class="btn btn-success btn-lg">Pseudo Submit</button>
<p>{{model.firstName}} - {{model.lastName}}</p>
</script>
what s wrong why model not binding in template and alert retunn model is null
Your setupController and model methods from TestingRoute aren't being called. Because your controller is created by the render view helper, not by a transition.
For example using the following works:
template
<script type="text/x-handlebars" data-template-name="testing">
{{input valueBinding="model.firstName"}}
{{input valueBinding="model.lastName"}}
<button {{action submitAction target="controller"}} class="btn btn-success btn-lg">Pseudo Submit</button>
<p>{{model.firstName}} - {{model.lastName}}</p>
</script>
javascript
App = Ember.Application.create({});
App.Router.map(function() {
this.route('testing', { path: '/' })
});
App.Person = Ember.Object.extend({
firstName: "r",
lastName: "issa"
});
App.TestingRoute = Ember.Route.extend({
model: function () {
return App.Person.create();
},
setupController: function (controller, model) {
debugger
controller.set("model", model);
}
});
App.TestingController = Ember.ObjectController.extend({
actions: {
submitAction: function () {
alert("My model is :" + this.get("model"));
}
}
});
Here is the fiddle http://jsfiddle.net/marciojunior/8DaE9/
Also, the use of actions in controllers is deprecated in favor of using the actions: { ... } object
Copied example from emberjs official site called Mailbox (under ROUTING).
App.Mailbox = Em.Object.extend();
App.Mailbox.reopenClass({
find: function(id) {
if (id) {
return App.FIXTURES.findBy('id', id);
} else {
return App.FIXTURES;
}
}
});
App.Router.map(function() {
this.resource('mailbox', { path: '/:mailbox_id' }, function() {
this.resource('mail', { path: '/:message_id' });
});
});
App.ApplicationRoute = Em.Route.extend({
model: function() {
return App.Mailbox.find();
}
});
App.MailRoute = Em.Route.extend({
model: function(params) {
return this.modelFor('mailbox').messages.findBy('id', params.message_id);
}
});
fixtures:
App.FIXTURES = [
{
name: "Inbox",
id: "inbox",
messages: [
{
id: 1,
subject: "Welcome to Ember",
from: "tomster#emberjs.com",
to: "user#example.com",
date: new Date(),
body: "Welcome to Ember. We hope you enjoy your stay"
}, {
id: 2,
subject: "Great Ember Resources",
from: "tomster#emberjs.com",
to: "user#example.com",
date: new Date(),
body: "Have you seen embercasts.com? How about emberaddons.com?"
}]}, {
name: "Spam",
id: "spam",
messages: [
{
id: 3,
subject: "You have one the Nigerian lottery!!!111ONEONE",
from: "419#thereallotteryhonest.ng",
to: "user#example.com",
date: new Date(),
body: "You have ONE the lottery! You only have to send us a small amount of monies to claim your prize"
}]}, {
name: "Sent Mail",
id: "sent-mail",
messages: [
{
id: 4,
subject: "Should I use Ember",
from: "user#example.com",
to: "tomster#emberjs.com",
date: new Date(),
body: "Ember looks pretty good, should I use it?"
}]}];
and html:
<script type="text/x-handlebars">
<div class="url">URL: {{target.url}}</div>
<aside>
<ul>
<li><h2>Mailboxes</h2></li>
{{#each}}
<li>
{{#link-to "mailbox" this currentWhen="mailbox"}}
<span class="count">
{{messages.length}}
</span>
{{name}}
{{/link-to}}
</li>
{{/each}}
</ul>
</aside>
<section class="main">
{{outlet}}
</section>
</script>
<script type="text/x-handlebars" id="index">
<div class="index">
<h1>TomsterMail</h1>
<span class="tomster"></span>
</div>
</script>
<script type="text/x-handlebars" id="index">
<div class="mail">
<dl>
<dt>From</dt>
<dd>{{from}}</dd>
<dt>To</dt>
<dd>{{to}}</dd>
<dt>Date</dt>
<dd>{{date date}}</dd>
</dl>
<h4>{{subject}}</h4>
<p>{{body}}</p>
</div>
</script>
<script type="text/x-handlebars" id="mailbox">
<table>
<tr>
<th>Date</th>
<th>Subject</th>
<th>From</th>
<th>To</th>
</tr>
{{#each messages}}
{{#link-to "mail" this tagName=tr}}
<td>{{date date}}</td>
<td>{{view.isActive}}{{subject}}</td>
<td>{{from}}</td>
<td>{{to}}</td>
{{/link-to}}
{{/each}}
</table>
{{outlet}}
</script>
<script type="text/x-handlebars" id="mailbox/index">
<div class="mailbox-index">
Select an email
</div>
</script>
When I go to url /index.html#/inbox/1 following exception thrown:
Assertion failed: Cannot call get with 'id' on an undefined object.
I have web application which needs same functionality, but with server requests (not from FIXTURES)
Try changing your code for retrieving the model:
return this.modelFor('mailbox').get('messages').findBy('id', params.message_id);
In Ember, you need to use get() to retrieve properties and associations
\
If i replace this.modelFor('mailbox').get('messages').findBy('id', params.message_id); with ajax call then everything works as expected
App.MailRoute = Em.Route.extend({
model: function(params) {
var ref = this;
return $.get("/inbox/"+params.message_id).then(function(data){
return data.findBy('id', params.message_id);
});
}
});
});
I need to create an application with routes:
/users - list of users
/users/123 - user info
/users/123/items - list of user items
/users/123/items/456 - items info
I wrote this code here
$(function() {
var App = window.App = Ember.Application.create({LOG_TRANSITIONS: true});
App.Router.map(function() {
this.resource("users", {path: '/users'}, function() {
this.resource("user", {path: '/:user_id'}, function() {
this.resource("items", {path: '/items'}, function() {
this.route("item", {path: '/:item_id'});
});
});
});
});
App.Store = DS.Store.extend({
revision: 11,
adapter: "DS.FixtureAdapter"
});
//ROUTES
App.UsersIndexRoute = Ember.Route.extend({
model: function() {
return App.User.find();
}
});
App.UsersUserIndexRoute = Ember.Route.extend({
model: function(params) {
return App.User.find(params.user_id);
},
setupController: function(controller, model) {
controller.set('content', model);
}
});
//DATA
App.User = DS.Model.extend({
name: DS.attr('string'),
items: DS.hasMany('App.Item')
});
App.Item = DS.Model.extend({
name: DS.attr('string')
});
App.User.FIXTURES = [
{
id: 1,
name: 'Joe',
items: [1, 2]
}, {
id: 2,
name: 'John',
items: [2, 3]
}
];
App.Item.FIXTURES = [
{
id: 1,
name: 'Item 1',
}, {
id: 2,
name: 'Item 2',
}, {
id: 3,
name: 'Item 3',
}
];
return true;
});
And templates:
<script type="text/x-handlebars" data-template-name="application">
<div>
<h1>ember routes</h1>
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="index">
<h2>Hello from index</h2>
{{#linkTo 'users'}}users area{{/linkTo}}
</script>
<script type="text/x-handlebars" data-template-name="users">
<h2>users area</h2>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="users/index">
<h3>users list</h3>
{{#each user in controller}}
{{#linkTo "user" user}}{{user.name}}{{/linkTo}}<br/>
{{/each}}
</script>
<script type="text/x-handlebars" data-template-name="users/user">
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="users/user/index">
<h4>user {{name}} index</h4>
</script>
<script type="text/x-handlebars" data-template-name="users/user/items">
<h4>user {{name}} items</h4>
{{outlet}}
</script>
If I go to /users , I see a list of users - its ok.
If I go to /users/1 I see message in browser console: "Transitioned into 'users.user.index'", but the content of the template 'users/user/index' is not showing.
I do not understand why, because I have App.UsersUserIndexRoute
Maybe I missed something?
if i'm not mistaken, using a UserIndexRoute (instead of a UsersUserIndexRoute - routes that are defined as resources usually don't have their parent routes' names prepended) with the model hook
model: function(params) {
return this.modelFor("user");
}
(and a corresponding template) should do the trick.
I am getting my feet wet with Ember.JS StateManager, and I am currently following the online documentation at: http://emberjs.com/api/classes/Ember.StateManager.html
I have done my best with this fiddle but cannot seem to get anything visual out at all. I have done numerous searches here at SOF and Google.
I have three states with three list item which trigger these states in view. I have placed a "ready function" within "Application.create({}" which fires, but as soon as the StateManager is initialized, "ready function" doesn't fire. I would highly appreciate your input and help.
Here is the fiddle: http://jsfiddle.net/exciter/NRmHc/12/
APP CODE
$(function(){
App = Ember.Application.create({
ready: function(){
//alert("APP INIT");
}
});
App.stateManager = Ember.StateManager.create({
showFirstState: function(manager){
App.stateManager.transitionTo('startupState');
},
showSecondState: function(manager){
App.stateManager.transitionTo('second');
},
showThirdState: function(manager){
App.stateManager.transitionTo('third');
},
showFourthState: function(manager){
App.stateManager.transitionTo('fourth');
},
// INIT STATE
initialState: 'startupState',
startupState: Ember.State.create({
templateName: 'startup',
classNames: ['state','black'],
enter: function() { alert("STARTUP ENTERED"); }
}),
second: Ember.State.create({
templateName: 'second',
classNames: ['state','orange'],
enter: function() { alert("SECOND ENTERED"); }
}),
third: Ember.State.create({
templateName: 'third',
classNames: ['state','lime'],
enter: function() { alert("THIRD ENTERED"); }
}),
fourth: Ember.State.create({
templateName: 'fourth',
classNames: ['state','blue'],
enter: function() { alert("FOURTH ENTERED"); }
}),
});
App.initialize();
});
HTML:
<!-- CHECK TO SEE IF CSS IS FUNCTIONAL
<div id="state" class="state blue">
STATE
</div>
-->
<script type="text/x-handlebars">
<nav>
<ul>
<li {{action "showFirstState" target="App.stateManager"}}>First State</li>
<li {{action "showSecondState" target="App.stateManager"}}>Second State</li>
<li {{action "showThirdState" target="App.stateManager"}}>Third State</li>
<li {{action "showFourthState" target="App.stateManager"}}>Fourth State</li>
</ul>
</nav>
</script>
<script type="text/x-handlebars" data-template-name="startup">
<h2> STARTUP STATE </h2>
</script>
<script type="text/x-handlebars" data-template-name="second">
<h2>SECOND STATE</h2>
</script>
<script type="text/x-handlebars" data-template-name="third">
<h2>THIRD STATE</h2>
</script>
<script type="text/x-handlebars" data-template-name="fourth">
<h2>THIRD STATE</h2>
</script>
CSS:
nav { background-color:#e9e9e9; padding: 1em 0 1em 0; }
nav li { display: inline; cursor: pointer; padding:0 1em 0 1em;}
.state { width:700px; height:500px; margin:0 auto; padding:0; background-color:#c9c9c9; }
.black { background-color:#666; }
.blue { background-color:#6699cc; }
.orange { background-color:#FF6600; }
.lime { background-color:#CCFF33; }
I get the feeling that what you want is not a statemanager but a router. Have a look at this link for further info.