where to define a bound attribute in ember - ember.js

I am trying to have an input text field be disabled by default and then be updatable to being able to be edited.
I have
{{input value=name disabled=entryNotAllowed }} <br /> <button {{action "canEdit"}}>Contract</button>
but where do I define entryNotAllowed where I set it to true. I tried on the model, the route, and the controller but none of them seemed to work.
I thought the controller most likely so I added this:
Hex.MenuController = Ember.Controller.extend({
entryNotAllowed: true
});
or in Route
Hex.MenuRoute = Ember.Route.extend({
entryNotAllowed: true,
actions: {
canEdit: function() {
but no dice. Any ideas on how to get this to work?

The context of your template defaults to the controller, so you can define/modify entryNotAllowed from there.
App
App = Ember.Application.create();
App.IndexController = Ember.Controller.extend({
entryNotAllowed: true,
actions: {
canEdit: function() {
this.set('entryNotAllowed', !this.get('entryNotAllowed'));
}
}
});
Template
<script type="text/x-handlebars">
<h2>Welcome to Ember.js</h2>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
{{input value=name disabled=entryNotAllowed }}<br />
<button {{action "canEdit"}}>Contract</button>
</script>
JSBin Example

Related

Set controller for template rendering

I recently decided to look into Ember.js after having spent the last two years with KO. The first thing to notice is that the complexity seems a TAD steeper but I shall prevail :)
Now, I seem to need to hardcode the controller for a certain template which seems weird:
App.IndexRoute = Ember.Route.extend({
renderTemplate: function() {
this.render('todosList', { into: 'application' });
}
});
App.todosController = Ember.ArrayController.create({
content: [App.Todo.create(), App.Todo.create()]
});
<script type="text/x-handlebars" data-template-name="application">
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="todosList">
<ul id="todo-list">
{{#each todo in App.todosController.content}}
<li>
<label {{bindAttr class="todo.isCompleted"}}>{{view Ember.Checkbox checkedBinding="todo.isCompleted"}} {{todo.title}}</label>
<button {{action 'removeTodo' todo target="App.todosController"}}>Ta bort</button>
</li>
{{/each}}
</ul>
{{view Ember.TextField valueBinding="App.todosController.newTodoText"}}
<button {{action 'newTodo' App.todosController.newTodoText target="App.todosController"}}>New todo</button>
</script>
I tried setting controller: 'App.todosController' in the render() call but nothing. The #each in the view accepts nothing else than App.todosController.content which doesn't seem right. Why do I even need to explicitly state that it's the content it should read, isn't that set automatically?
Thankful for any help, Ember seems to have its niceties but in the beginning much is confusing.
Short answer first:
working jsbin: http://jsbin.com/usaluc/8/edit
Longer answer:
You had some misconceptions in your code that I've changed to be more ember-like, this results in this very simple example.
todosList template
<script type="text/x-handlebars" data-template-name="todosList">
<ul id="todo-list">
{{#each todo in controller}}
<li>
<label {{bindAttr class="todo.isCompleted"}}>
{{view Ember.Checkbox checkedBinding="todo.isCompleted"}} {{todo.title}}
</label>
<button {{action 'removeTodo' todo target="controller"}}>Remove toto</button>
</li>
{{/each}}
</ul>
{{view Ember.TextField valueBinding="newTodoText"}}
<button {{action 'newTodo' newTodoText target="controller"}}>New todo</button>
</script>
IndexRoute
When using renderTemplate to make sure the correct controller is used you should define it in the hash you are passing into the render function:
App.IndexRoute = Ember.Route.extend({
renderTemplate: function() {
this.render('todosList', {
into: 'application',
controller: 'todosList'
});
}
});
Route map
Since you dind't post your route map, and furthermore because your are using the IndexRoute renderTemplate hook I assumed your todosList is rendered directly when visiting '/', so just to be concise here a simple router map the renders the todosList template when visiting '/'
App.Router.map(function() {
this.resource('todosList', {path: '/'});
});
TodosListRoute
Now that you have a TodosListRoute in where you want to set to correct controller content, you should hook into the setupController function and do just that:
App.TodosListRoute = Ember.Route.extend({
setupController: function(controller, model) {
var myTodos = [
App.Todo.create({title: 'Drink water', text:'foo'}),
App.Todo.create({title: 'Bring out the trash', text:'bar'})
];
controller.set('content', myTodos);
}
});
TodosListController
The TodosListController looks fairly simple so far only including the two functions newTodo and removeTodo using the title value passed from the action helper in your template:
App.TodosListController = Ember.ArrayController.extend({
newTodo: function(title) {
var todo = App.Todo.create({title: title, text:'foo'});
this.get('content').pushObject(todo);
},
removeTodo: function(todo) {
this.get('content').removeObject(todo);
}
});
Hope it helps.

Ember.js Router: Embedded resources

I'm creating an Ember application to display twitter feeds but I am having trouble with displaying individual tweets through embedded resources.
The code is as follows:
Templates
<script type="text/x-handlebars" data-template-name="tweets">
<div id="stream">
{{#each tweet in controller}}
<div class="tweet">
<p class="tweet_text">{{tweet.text}}</p>
<p> {{#linkTo "tweet" tweet}} {{tweet.id}} {{/linkTo}}</p>
</div>
{{/each}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="tweet">
<div id="detail">
{{text}}
</div>
</script>
Router
window.App = Ember.Application.create({
LOG_TRANSITIONS: true
});
App.Router.map(function(){
this.resource('tweets',function(){
this.resource('tweet',{path: ':tweet_id'})
});
});
// (1) App.Router.map(function(){
// this.resource('tweets')
// this.resource('tweet',{path: ':tweet_id'})
// });
App.IndexRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('tweets');
}
});
App.TweetsRoute = Ember.Route.extend({
model: function(){
var me = [];
$.getJSON("http://search.twitter.com/search.json?q=emberjs&rpp=200&count=200&callback=?",
{},
function (data) {
$.each(data.results,function(k,tweet){
var tweet = App.Tweet.create({
created_at: tweet.created_at,
from_user: tweet.from_user,
profile_image_url: tweet.profile_image_url,
text: tweet.text,
id: tweet.id
});
me.pushObject( tweet );
});
});
return me;
}
});
Objects & Controllers
App.TweetsController = Ember.ArrayController.extend({});
App.Tweet = Ember.Object.extend({
created_at: "",
from_user: "",
profile_image_url: "",
text: "",
id: 0
})
As you can see, I have a commented our router (1) which works in finding the correct tweet, and rendering it in the tweet template. However, I would like this route to be nested so that I can implement it as a Master-Detail application.
Using the LOG_TRANSITIONS, I can see that the correct routes are initialised, but I cannot get the nested resource path to render.
Any ideas would be hugely appreciated, thanks in advance.
I got this working. For anyone stuck on something similar, this is how I did it:
Templates - Changed the {{#linkTo}} "tweet"... to {{#linkTo}} "tweets.tweet"... AND added an {{outlet}}
<script type="text/x-handlebars" data-template-name="tweets">
<div id="stream">
{{#each tweet in controller}}
<div class="tweet">
<p class="tweet_text">{{tweet.text}}</p>
<p> {{#linkTo "tweets.tweet" tweet}} {{tweet.id}} {{/linkTo}}</p>
</div>
{{/each}}
</div>
{{ outlet }}
</script>
Router - Changed 'this.resource' to 'this.route'
App.Router.map(function(){
this.resource('tweets',function(){
this.route('tweet',{path: ':tweet_id'})
});
});
Caveat
I think this is a workaround and that the nested resource was the correct approach in this context. I understand that a nested route should be "a verb" or action route. I would still be grateful if anyone knows the correct approach to the question but hope the above helps others where relevant.

Emberjs rendering wrong template

I am working with EmberJs and can't figure out why the following code won't render the 'new' template. When I navigate to /shops, I get a list of shops and a create button linking to '/shops/new', but when I click create, the 'new' template isn't rendered and instead stays the same as 'shops'. I can navigate to each individual shop fine, just not new.
App.js
window.App = Ember.Application.create();
App.Router.reopen({
location: 'history'
});
// Router
App.Router.map(function() {
this.resource('shops', function() {
this.route('new');
});
this.resource('shop', { path: '/shops/:shop_id' });
});
App.ShopsRoute = Ember.Route.extend({
model: function() {
return App.Shop.find();
}
});
App.ShopsNewRoute = App.ShopsRoute.extend({
model: function() {
return App.Shop.createRecord();
},
setupController: function( controller, model ) {
return this._super(),
controller.set( 'content', model )
}
});
App.ShopsNewController = Ember.ObjectController.extend();
// Models
App.Store = DS.Store.extend({
revision: 11,
adapter: DS.RESTAdapter
});
App.Shop = DS.Model.extend({
name: DS.attr('string'),
body: DS.attr('string'),
});
Index.html
<!DOCTYPE html>
<html>
<head>
<title>Ember/Rails App</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<script type="text/x-handlebars" data-template-name="application">
<div class="row">
<div class="twelve columns">
<h1>Ordr</h1>
<hr>
{{outlet}}
</div>
</div>
</script>
<script type="text/x-handlebars" data-template-name="shops/new">
<h2>New Shop</h2>
</script>
<script type="text/x-handlebars" data-template-name="shops">
{{#each shop in controller}}
{{#linkTo "shop" shop}} {{ shop.id }}{{/linkTo}}
{{/each}}
{{#linkTo 'shops.new'}}Create{{/linkTo}}
</script>
<script type="text/x-handlebars" data-template-name="shop">
<h2>{{name}}</h2>
<p>{{body}}</p>
</script>
</body>
</html>
The way you have set up your routes and templates, you are telling Ember that you want to navigate to shops.new and keep all the list of shops showing even while you are in shops.new.
If that is in fact the scenario that you want, all you need to do is add an {{outlet}} inside the shops template:
<script type="text/x-handlebars" data-template-name="shops">
{{#each shop in controller}}
{{#linkTo "shop" shop}} {{ shop.id }}{{/linkTo}}
{{/each}}
{{#linkTo 'shops.new'}}Create{{/linkTo}}
{{outlet}}
</script>
However, if that is not what you really intend, and you actually want the list of shops to be hidden when you transition to shops.new, then you will need to change a couple of things.
change your App.ShopsRoute to App.ShopsIndexRoute :
App.ShopsIndexRoute = Ember.Route.extend({
model: function() {
return this.store.find('shop');
}
});
and your shops template to shops/index template:
<script type="text/x-handlebars" data-template-name="shops/index">
{{#each shop in controller}}
{{#linkTo "shop" shop}} {{ shop.id }}{{/linkTo}}
{{/each}}
{{#linkTo 'shops.new'}}Create{{/linkTo}}
</script>
Any of those 2 methods should fix your problem, depending on what your intentions are.

handlebars view not refreshing when {{#if}} {{else}} condition changes

(edit: simplified things a bit below)
I have a handlebars template with an {{#if etc}} conditional, and when I change the associated data the view updates the first time, but then does not continue to update on subsequent changes. I am toggling a boolean that is in the condition, and I know the toggle is running and switching the property because I can watch it do so on the console, but the actual view, a I said, only refreshes once. In my html file this looks like this:
<script type="text/x-handlebars" data-template-name="application">
<body>
<div class="row">
{{#if App.Nav.show}}
{{outlet nav}}
{{/if}}
<div class="span10">
<h1>Hello</h1>
{{outlet}}
</div>
</div>
</body>
</script>
and a bit further on, to toggle:
<script type="text/x-handlebars" data-template-name="people">
<a {{action toggleMenu}}> toggle </a>
</script>
and in the javascript:
App.NavController = Ember.Controller.extend();
App.NavView = Ember.View.extend({
templateName: 'nav'
});
App.Nav = Ember.Object.create({
show: true
});
and finally the relevant bits of the router:
App.Router = Ember.Router.extend({
enableLogging: true,
root: Ember.Route.extend({
index: Ember.Route.extend({
route: '/',
showPerson: Ember.Route.transitionTo('aName'),
toggleMenu: function(){
console.log('Changing the toggle!');
App.Nav.toggleShow();
},
connectOutlets: function(router){
router.get('applicationController').connectOutlet('nav', 'nav');
router.get('applicationController').connectOutlet('allPeople', unrelated_function())
}
})
})
});
I would say to put your if into your view. Something like this:
<script type="text/x-handlebars" data-template-name="people">
<a {{action toggleMenu}}> toggle </a>
{{#if App.Nav.show}}
<div>navigation</div>
{{/if}}
<div class="span10">
<h1>Hello {{name}}</h1>
</div>
</script>
Then your application view should look something like this:
<script type="text/x-handlebars" data-template-name="application">
<body>
<div class="row">{{outlet}}</div>
</body>
</script>
Let me know if you tried it and it worked.
I did not use connectOutlet to display the view, let me know if there is some purpose behind using connectOutlet method, Meanwhile here is my implementation of toggling the view visibility

data-template-name issue in emberjs

There is a strange issue am facing with ember.js, i.e when I add "data-template-name" attribute to the script tag, nothing is working. If data-template-name name is removed, things are working fine.
This is NOT WORKING
<script data-template-name="my-template" type="text/x-handlebars">
Input:
{{#view App.MyView}}
{{view Ember.TextField
valueBinding="view.theValue"
placeholder="input ..." }}
{{/view}}
</script>
Now if **data-template-name="my-template"** is removed it works fine.
I mean, In UI TextField is visible.
<script type="text/x-handlebars">
Input:
{{#view App.MyView}}
{{view Ember.TextField
valueBinding="view.theValue"
placeholder="input ..." }}
{{/view}}
</script>
App.MyView = Ember.View.extend({
templateName: 'my-template',
theValue: null,
init: function(){
this._super();
this.set('theValue','asdf');
},
keyDown: function(e){
if(e.keyCode === 13){
alert(this.get('theValue'));
}
}
});
Ok, don't worry about the jsfiddle, it's a good start :). There is a link on the ember.js site, where you can find a starting point, including Ember.js related sources: http://emberjs.com/community/
That beeing said, when creating an Ember.js application like this, there is an implicit default anonymous template, in wich you can then define yours.
<!-- default template, introducing the view App.MyView -->
<script type="text/x-handlebars">
{{view App.MyView}}
</script>
<!-- template of App.View -->
<script data-template-name="my-template" type="text/x-handlebars">
Input:
{{view Ember.TextField
valueBinding="view.theValue"
placeholder="input ..."}}
</script>​
javacript:
App.MyView = Ember.View.extend({
templateName: 'my-template',
theValue: null,
init: function(){
this._super();
this.set('theValue','asdf');
}
});​
Here is a working example of your sample:
http://jsfiddle.net/6p6XJ/171/