Ember.js handlebars if, else statement - javascript

I'm hoping someone can explain what I'm doing wrong here. I'm using Ember.js with handlebars templates, I've tried a number of ways to get handlebars #if else working for me but it always returns both the contents of if and else.. Here's the code I'm currently using.
App.js:
App = Ember.Application.create({
selectedView: "Home",
IsHome: function() {
this.get('selectedView') === 'Home'
}.property('selectedView')
});
index.html head contains:
<script type="text/x-handlebars" data-template-name="home-view">
Hello, This is the home view.
</script>
<script type="text/x-handlebars" data-template-name="edit-account">
Hello, This is the account edit view.
</script>
and in the body:
<script type="text/x-handlebars">
{{#if App.IsHome}}
{{view HomeView}}
{{else}}
{{view editAccountView}}
{{/if}}
</script>
This ends up showing both views in the body of the page. Any advice is appreciated,
thanks
Steve

The fundamental reason for your problem is the Handlebars view helper ( {{view MyView}} ) expects a path parameter to an Ember “class”, not an instance of a class. To create a view class use the extend method of Ember.View. The Handlebars view helper will instantiate your view class and append it to the document for you.
See this post for more information on the Ember object model and the differences between Ember’s extend and create methods: http://ember-object-model.notlong.com.
Here is your example with a few changes made to correct the points I made above. http://jsfiddle.net/ethan_selzer/kcjzw/217/
Regards,
Ethan

That's because you are appending both views (homeView and editAccountView) manually with appendTo.
Also, avoid defining views within the App create() function. Therefore, create your App:
App = Ember.Application.create({
ready: function() {
App.MainView.create().append();
}
});
where App.MainView is your top-level view defined by:
App.MainView = Ember.View.extend({
templateName: 'main-view',
selectedView: "Home",
isHome: function() {
this.get('selectedView') === 'Home'
},
homeView: Ember.View.extend({
templateName: 'home-view'
}),
editAccountView: Ember.View.extend({
templateName: 'edit-account'
})
});
with the handlebars template:
<script type="text/x-handlebars" data-template-name="main-view">
{{#if view.isHome}}
{{view view.homeView}}
{{else}}
{{view view.editAccountView}}
{{/if}}
</script>

Related

Ember.js Render multiple views inside static HTML

I'm new to Ember and I'm stuck trying to render views.
The application in context is not a single page application but so far Ember has been playing nice until I started dealing with views.
I'm trying to render more than one view on a single page (which is like a dashboard and has tons of static HTML and a few containers, one for each view).
Sample HTML:
Let's say I would like to render two lists, one inside the "left-container" div and the other inside the right container.
<div class="static-header></div>
<!-- more static content goes here -->
<div id="left-container"></div>
<!-- more static content goes here -->
<div id="right-container"></div>
...
I've tried creating different views and inserting them using the appendTo method (which is described in the Defining a View section of Ember guides) but it throws the error:
Container was not found when looking up a views template. This is most likely due to manually instantiating an Ember.View. See: http://git.io/EKPpnA
and I couldn't find my way using the link that it points to.
Ember code:
var App = Ember.Application.create({});
App.HomeViewLeft = Ember.View.extend({
templateName: 'home-left',
});
var view = App.HomeViewLeft.create();
view.appendTo('#left-container');
I have also tried using a ContainerView as described in Ember api docs:
App.HomeViewLeft = Ember.View.extend({
templateName: 'home-left',
});
var containerView = Ember.ContainerView.create({
classNames: ['container-view'],
});
containerView.pushObject(App.HomeViewLeft.create());
containerView.appendTo('left-container');
But I get the same error.
How should I render each view inside the #left-container and #right-container respectively?
Thanks in advance.
Template:
<div id="here"></div>
<script type="text/x-handlebars" data-template-name="components/my-foo">
{{text}}
</script>
JS:
App = Ember.Application.create({});
Ember.Application.initializer({
name: 'stand-alone-components',
initialize: function(container, application) {
App.MyFooComponent.create({text: 'Hello World', container: container}).appendTo('#here');
}
});
App.MyFooComponent = Ember.Component.extend({
init: function() {
this._super();
this.set('layout', Ember.TEMPLATES['components/my-foo']);
}
});
http://emberjs.jsbin.com/nekowidera/1/edit?html,js,output
It looks like you are trying to make views behave like partials
Move anything static into a partial and include it in your main template like so:
{{partial "header"}}
The lists you want to render can be turned into a component (if the only thing that changes in them is the data).
So you end up with a single view that contains partials and components:
<div class="static-header>{{partial "header"}}</div>
{{partial "static-content"}}
<div id="left-container">{{list-component data=firstList}}</div>
{{partial "static-content"}}
<div id="right-container">{{list-component data=secondList}}</div>
...

Ember replacing html content

I've just started learning ember am trying to make a link that replaces other html, currently I have written this:
<script type="text/x-handlebars" id="about">
{{#each}}
<h2>{{#link-to 'quarter' this}}{{title}}{{/link-to}}</h2>
{{/each}}
</script>
Now I want to make the quarter content load in the same about template replacing that each loop, how should I go about it?
Again, I'm totally new to ember and it's own guides section is a bit too convoluted for me to find the answer.
Since About is not a resource route, you have to use custom outlet in your about template:
<div class="quarter">{{outlet quarter}}</div>
Then in your QuarterRoute:
App.QuarterRoute = Ember.Route.extend({
renderTemplate: function() {
this.render({ outlet: 'quarter' });
}
});
If you have a Quarters resource routes, you could just nest your routes and just a have simple outlet in your quarters template.
App.Router.map(function() {
this.resource('quarters', function() {
this.resource('quarter');
});
});

Setup Controllers Created with Render in Each Helper

In my Ember template, I render an arbitrarily-sized array of displayItems like so:
<script type="text/x-handlebars" id="display">
<h1>{{name}}</h1>
<hr>
<div id="display-items">
{{#each displayItem in displayItems itemController="chart"}}
{{render "chart" displayItem}}
{{/each}}
</div>
</script>
However, I need to initialize some properties on the chart controller before the chart view renders. I know that for predefined view and controller structures, you can use the setupController hook on a route, but since these controllers are created dynamically, I thought I could use the chart controller's init property like so:
...other controller code
init: function() {
var self = this;
self._super();
self.get("views")
.then(function(views) {
self.set("currentView", views.objectAt(0));
});
}
...
But although the init hook is called, it is called too late--the view has already rendered with undefined values. Is there a way to setup dynamically-created controllers before their views render?
What you need to do is to create a property in your 'chart' controller, that will be observing all properties you need to be filled int before displaying the view. First off, I would recommend you to change this:
{{#each displayItem in displayItems itemController="chart"}}
{{render "chart" displayItem}}
{{/each}}
to this:
{{#each displayItem in displayItems}}
{{render "chart" displayItem}}
{{/each}}
'render' will instantiate a new charController for you, and its corresponding view. Then, in your 'chartController', add a property listening to all properties you need before rendering the view:
App.ChartController = Ember.ObjectController.extend({
isAllInformationComplete: function() {
return !Ember.isEmpty('property1') && !Ember.isEmpty('property2');
}.property('property1', 'property2')
});
and in your view, wrap your code in an if statement:
<script type="text/x-handlebars" data-template-name="chart">
{{#if isAllInformationComplete}}
All your view html, handlebars, etc...
{{/if}}
</script>
here is a Fiddle for more details.

How to set a controller's content property to an array of models without a corresponding route?

I'm using the {{render}} handlebars helper in one of my templates to (attempt to) render the template of another route on the same page. So for example:
<script type="text/x-handlebars" data-template-name="index">
{{#each model}}
{{name}}<br />
{{/each}}
{{render "people"}}
</script>
<script type="text/x-handlebars" data-template-name="people">
{{#each controller}}
{{name}}<br />
{{/each}}
</script>
In my people controller I set the model as usual:
App.PeopleRoute = Ember.Route.extend({
model: function() {
return App.People.find();
}
});
If I visit my people route directly (/people), I get a list of people. In my main template where the people template is being rendered into another template, the render helper doesn't call the PeopleRoute, so the model is never set (as far as I understand it).
Is there a way for me to set the content property on the PeopleController to the list of people objects?
I can't get any variation of this to work:
App.PeopleController = Ember.ArrayController.extend({
content: function() {
return App.People.find();
}
});
The render helper doesnt make any transitions and hence the model hook will not get called.. It just renders the template in the current context with the same-named controller... You can pass an optional model to the render helper which binds to the content of the same-named controller... Ember API
<script type="text/x-handlebars" data-template-name="index">
{{#each model}}
{{name}}<br />
{{/each}}
{{render "people" model}}
</script>
Sample fiddle here

Using Ember.js and Handlebars, what is the difference between binding a template to a class view vs instance of view?

Case I.Binding template to instance of view.
For example, let's say I have a template:
<script type="text/x-handlebars" data-template-name="instance-template">
<b> Name: </b> {{ name }}
</script>
I can then bind an instance of view to it and append to the document ( for simplicity sake the param name is declared in view, as opposed to binding to some control layer) :
App.instanceView = Ember.View.create({
templateName: 'instance-template',
name: 'hello world'
}).append();
What exactly is going on behind the scenes here? By specifying a template name, is this instance of view somehow taking a template and compiling it with the parameters passed in the background?
Case II. Binding template to class view, template not named.
If, however, I want to bind a template to a class view such as:
App.ViewClass = Ember.View.extend({
name: 'hello world',
});
The documentation uses a template of this form:
<script type="text/x-handlebars">
{{ #view App.ClassView }}
This part renders: {{ name }}
{{ /view }}
</script>
Please note, when I do this, for some reason this does not work. The quote 'This part renders: ' in the template actually renders, however the {{ name }} tag is not rendered. I have no idea why.
Case III. template bind to class view, template is named.
In addition, if I name the template above:
<script type="text/x-handlebars" data-template-name = 'class-template'>
{{ #view App.ClassView }}
This part renders: {{ name }}
{{ /view }}
</script>
and change the view to
App.ViewClass = Ember.View.extend({
templateName: 'class-template',
name: 'hello world',
});
nothing renders at all. Again I do not see what is going on here.
Case 1
Yah pretty much. The view is rendering (and we are assuming the context is the view) then when we see {{name}} this will be equivalent to instanceView.get('name').
Case 2
Anonymous templates do not change context. When you define a template inside of {{#view}} the context won't change. To get the view's context that was used with the {{#view}} helper you'll need to use view.name. For example:
App.ViewClass = Ember.View.extend({
name: 'hello world',
});
<script type="text/x-handlebars">
{{name}} <!-- lets pretend this is "something else" -->
{{#view App.ClassView}}
This part renders: {{name}} <!-- "something else" -->
{{view.name}} <!-- "hello world" -->
{{/view}}
</script>
Case 3
This example makes no sense and should probably have an assertion fail with Ember (non minified version). You are defining a view that uses a template, then inside that template rendering that same view again with an anonymous template. If this is you intended meaning could you please provide a use case because there is probably a much simpler way to go about waht you are trying to accomplish.

Categories

Resources