handlebars view not refreshing when {{#if}} {{else}} condition changes - ember.js

(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

Related

How do I pass model information to this each statement in a nested template?

I have an index route where I need to populate a menu in one outlet based on a list of models. However I cannot get the models to be represented in the each statement.
Here is the Category Model:
App.Category = DS.Model.extend({
title: DS.attr('string'),
parent: DS.belongsTo('App.Category')
})
And here is the indexRoute where I render it
App.IndexRoute = Em.Route.extend({
renderTemplate: function(){
this.render('index')
this.render('categoryMenu',
{
outlet: 'sidebar',
into: 'index',
model: function() {
return App.Category.find()
},
controller: App.CategoriesController
})
this.render('badgesList',{
outlet: 'badgesList',
into: 'index'
})
}
})
Index Template:
<script type="text/x-handlebars" data-template-name="index">
<div class="span3">
{{outlet sidebar}}
</div>
<div class="span8">
{{outlet badgesList}}
</div>
</script>
Nested Category Template
<script type="text/x-handlebars" data-template-name="categoryMenu">
<ul>
{{#each model}}
{{title}}
{{/each}}
</ul>
</script>
I have tried to change the each statement to several different things like controller or item in model but nothing is displayed.
Thank you for any help!
Make yourself CategoriesController first like this:
App.CategoriesController = Ember.ArrayController.extend({
content: function () {
return App.Category.find()
}.property()
});
rename your template just to categories
<script type="text/x-handlebars" data-template-name="categories">
<ul>
{{#each model}}
{{title}}
{{/each}}
</ul>
</script>
in your index template replace {{outlet}} with {{render 'categoies'}}
<script type="text/x-handlebars" data-template-name="index">
<div class="span3">
{{render 'categoies'}}
</div>
<div class="span8">
{{outlet badgesList}}
</div>
</script>
as last thing remove the call rendering categoryMenu.

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.

Using multiple named outlets and a wrapper view with no content in Emberjs

I'm trying to use multiple named outlets with Ember.js. Is my approach below correct?
Markup:
<script type="text/x-handlebars" data-template-name="application">
<div id="mainArea">
{{outlet main_area}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="home">
<ul id="sections">
{{outlet sections}}
</ul>
<ul id="categories">
{{outlet categories}}
</ul>
</script>
<script type="text/x-handlebars" data-template-name="sections">
{{#each section in controller}}
<li><img {{bindAttr src="section.image"}}></li>
{{/each}}
</script>
<script type="text/x-handlebars" data-template-name="categories">
{{#each category in controller}}
<img {{bindAttr src="category.image"}}>
{{/each}}
</script>​
JS Code:
Here I set the content of the various controllers to data grabbed from a server and connect outlets with their corresponding views. Since the HomeController has no content, set its content to an empty object - a hack to get the rid of this error message:
Uncaught Error: assertion failed: Cannot delegate set('categories'
) to the 'content' property of object
proxy : its 'content' is undefined.
App.Router = Ember.Router.extend({
enableLogging: false,
root: Ember.Route.extend({
index: Ember.Route.extend({
route: '/',
connectOutlets: function(router){
router.get('sectionsController').set('content',App.Section.find());
router.get('categoriesController').set('content', App.Category.find());
router.get('applicationController').connectOutlet('main_area', 'home');
router.get('homeController').connectOutlet('home', {});
router.get('homeController').connectOutlet('categories', 'categories');
router.get('homeController').connectOutlet('sections', 'sections');
}
})
})
});
​
If it's any help, I got this error because I was connecting to an Ember.ObjectController instead of Ember.Controller.

ember.js statemanager use for tabs

i have 3 tabs navigation and the content of each tab is different obviously.
i'm thinking about using StateManager in Emberjs to manager my tab views.
http://docs.emberjs.com/#doc=Ember.StateManager&src=false
is that a good idea? or is there a better router out there? i've looked at
sproutcore-routing
ember-routemanager
are those better than the statemanager? what's the reason not to use statemanager?
You can use something along this lines, see http://jsfiddle.net/pangratz666/e3wM7/:
Handlebars:
<script type="text/x-handlebars" >
<ul>
<li {{action "showFirst" target="App.stateManager"}} >First tab</li>
<li {{action "showSecond" target="App.stateManager"}} >Second tab</li>
</ul>
<div class="tab-content" ></div>
</script>
<script type="text/x-handlebars" data-template-name="first" >
first
</script>
<script type="text/x-handlebars" data-template-name="second" >
second
</script>​
JavaScript:
App.stateManager = Ember.StateManager.create({
rootElement: '.tab-content',
initialState: 'firstTab',
showFirst: function(manager) {
manager.goToState('firstTab');
},
showSecond: function(manager) {
manager.goToState('secondTab');
},
firstTab: Ember.ViewState.create({
view: Ember.View.extend({ templateName: 'first' })
}),
secondTab: Ember.ViewState.create({
view: Ember.View.extend({ templateName: 'second' })
})
});​
Also take a look at the blog post Anatomy of an Ember.js App Part I Redux: Routing and Outlets.

Can I access view property in {{#with}} scope?

I want to toggle visibility of element in {{#with}} scope, depending on the value of view's property.
I can access to view property in {{action}} in {{#with}}, but I can not access to view property in {{#with}.
Below is a sample program.
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script>!window.jQuery && document.write(unescape('%3Cscript src="js/libs/jquery-1.6.1.min.js"%3E%3C/script%3E'))</script>
<script src="http://cloud.github.com/downloads/emberjs/ember.js/ember-0.9.5.js"></script>
<script type="text/javascript">
var App = Em.Application.create();
App.Test = Em.View.extend({
content: {
description: 'names',
names: [{name: 'bob'}, {name: 'john'}]
},
viewDetail: false,
toggleDetail: function() {
this.set('viewDetail', true);
}
})
</script>
<script type="text/x-handlebars">
{{#view App.Test}}
{{#with content}}
{{description}}<br/>
{{#each names}}
{{name}}
{{/each}}
<br/>
<button {{action toggleDetail}}>toggle Detail</button> <!-- can access toggleDetail -->
{{#if viewDetail}} <!-- but can not access viewDetail... -->
…detail Description...
{{/if}}
{{/with}}
{{/view}}
</script>
Can I access to view property in {{#with}} scope ?
#with modifies the Handlebars context. You can go back up a level by using ../.
Give this a try:
{{#if ../viewDetail}}