When to render via render and when via view? - ember.js

I'm trying to figure out when to render a custom view with render and when via view. I know that rendering with render we get the full context (view, controller). But what about view? View is supposed to be for custom views and handing events.
The example below comes form ember data example
contacts.hbs
<div class="span3">
<div class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header">All contacts</li>
{{#each contact in controller}}
{{view App.ContactInListView contentBinding="contact"}}
{{/each}}
</ul>
</div>
</div>
<div class="span9">
{{outlet}}
</div>
contact_in_list_view.hbs
App.ContactInListView = Em.View.extend({
templateName: 'contact_in_list',
tagName: 'li',
classNameBindings: 'isActive:active',
isActive: function() {
return this.get('content.id') === this.get('controller.activeContactId');
}.property('controller.activeContactId')
});
contact_in_list.hbs
{{#linkTo "contact" contact}}{{contact.fullName}}{{/linkTo}}
Couldn't just I render contact_in_list with render and pass it some controller?
When should I use render and when view? What's the rule of thumb?

Couldn't just I render contact_in_list with render and pass it some controller?
The {{render}} helper can be passed a model but not controller. Probably what you want in this case is the {{each}} helper's itemController property
{{#each contact in controller itemController="contactInList"}}
{{view App.ContactInListView}}
{{/each}}
Have a look at API docs for Ember Handlebars.helpers
When should I use render and when view? What's the rule of thumb?
Use the {{render}} helper when you want to render a view/template in the current context using the singleton instance of the same-named controller.
Use the {{view}} helper when you want to render a view in the current context without changing to another controller. Like {{view Ember.TextField}}

Related

Creating a Lightbox Route in Ember.js

My authentication system uses lightboxes, so that when a user clicks "Sign In" or "Sign Up", a lightbox pops up for them to input their credentials. The page they were on remains rendered behind the lightbox, and when they're done signing in, the lightbox disappears and the view returns to the way it was. I can get this to work when I deviate from the conventional Ember route flow by using a lot of Jquery, but I'd prefer to integrate this more tightly into the rest of my Ember app.
The problem is, the conventional Ember route flow expects views and templates to be handled in a particular way. Specifically, a route such as /sign-in will render the sign-in template within the application template, erasing whatever was there before. Since I want to preserve the view that was there before, this approach doesn't work.
Is there a way to tell an Ember view not to erase the current view, but instead to render an independent view such as a lightbox?
You can use named outlets and render a template into the outlet, in my aplication template I has an outlet called modal, and two actions in the ApplicationRoute, openModal and closeModal. The open one receives a template name and uses the route method render to set the outlet content, the close one renders an empty template.
App.ApplicationRoute = Ember.Route.extend({
actions: {
openModal: function(modal) {
this.render(modal, {into:'application', outlet: 'modal'});
},
closeModal: function() {
this.render('empty', {into: 'application', outlet: 'modal'});
},
}
});
Html handelbars
<script type="text/x-handlebars" data-template-name="application">
{{! Other application template code}}
<button {{action openModal 'hellow.modal'}}>Open it!</button>
{{outlet modal}}
</script>
<script type="text/x-handlebars" data-template-name="empty"></script>
<script type="text/x-handlebars" data-template-name="hellow/modal">
<div class="modal">
<div class="modal-header">
Hellow
</div>
<div class="modal-footer">
<button {{action closeModal}}>Close</button>
</div>
</div>
</script>
This is adapted from http://nerdyworm.com/blog/2013/04/20/ember-modal-example/

Can't swap currentView of Ember.ContainerView in a #each

I'm trying to use the the currentView feature of an Ember.ContainerView in the context of a #each helper but it fails when currentView property is changed to another view.
My aim here is to allow editing an item of a list, by changing the regular view to an edit view when the user click a link.
Main template:
<ul>
{{#each itemController="person"}}
<li>{{view Ember.ContainerView currentViewBinding="cv"}}</li>
{{/each}}
</ul>
Template 'name' used to display a person :
{{firstName}} {{lastName}} <a {{action edit}}>edit</a>
Controller for the currentViewBinding property ('cv') and handling for the edit action.
App.PersonController = Ember.ObjectController.extend({
cv: Ember.View.extend({
templateName: 'name'
}),
edit: function() {
this.set('cv', Ember.View.extend({
templateName: 'nameEdit'
}));
}
})
'nameEdit' template corresponding to the view that needs to be displayed to edit the person object.
{{input type='text' value=firstName}} {{input type='text' value=lastName}}
The api guide says that:
When the currentView property is set to a view instance, it will be added to the ContainerView. If the currentView property is later changed to a different view, the new view will replace the old view.
But it's worse if I replace the cv property with a view instance (by using create() instead of extend()) as a re-render error is yield. See this question of mine.
Here is the jsFiddle to play with http://jsfiddle.net/fblanvil/tD3Ph/3/
I ended up not using ContainerView at all and using a simple if. But it doesn't explain why it's not possible to use a ContainerView this way in an #each helper. If someone thinks it's worth a Jira, put a comment and I'll do it.
<ul>
{{#each itemController="person"}}
<li>
{{#if editing}}
{{view templateName='nameEdit'}}
{{else}}
{{view templateName='name'}}
{{/if}}
</li>
{{/each}}
</ul>
Simple and effective after all...
App.PersonController = Ember.ObjectController.extend({
editing: false,
edit: function() {
this.set('editing', true);
}
})

Adding a new object to an ArrayController

I am attempting to create a basic CRUD setup for managing 'User' objects in Ember. I think I have my models and routes in order. I'm struggling with managing:
A) The proper controller setup for the (all) users page. I think that I should be creating an ArrayController, but it seems to work fine automatically. Does my Ember App know to make an array of individual 'user' objects? if so, how?
B) Passing data from InputFields. If you click 'Add User' in my example, I have made a form to create a user. When you click 'create', I'm not sure how to get the textField values, nor do I understand what to do with those values once I have them. How would I update my controller?
Again, here a jsbin of my code. Any guidance would be greatly appreciated.
Regarding A):
I assume you refer to the following route of your App. This model function returns an Array. Therefore Ember knows that it should use an ArrayController to render your UsersRoute.
App.UsersIndexRoute = Ember.Route.extend({
model: function() {
return App.User.find();
}
});
Regarding B): I have updated your code -> http://jsbin.com/ozilam/15/edit
I needed to update some of your names (controller and view) to match the naming conventions of Ember.
With Ember you do not have to use forms and manually read those values. Instead you create a new records, when you enter your Route:
App.UsersNewRoute = Ember.Route.extend({
setupController : function(controller){
controller.set("content", App.User.createRecord({}));
}
});
Inside your View you are binding on the properties of your record. As you see i also updated your button with an action helper.
<script type="text/x-handlebars" data-template-name="users/new">
<div class="row">
<div class="six columns">
<h3>New User Information</h3>
<form>
<label>First Name</label>
{{view Ember.TextField valueBinding='name_first'}}<br />
<label>Last Name</label>
{{view Ember.TextField valueBinding='name_last'}}<br />
<label>Email Address</label>
{{view Ember.TextField valueBinding='email_address'}}<br />
<label>SSN</label>
{{view Ember.TextField valueBinding='ssn'}}<br />
<button {{action create target="view"}} class="button">Create</button>
{{#linkTo users}}Cancel{{/linkTo}}
</form>
</div>
</div>
</script>
As those changes in the form get automatically propagated to your controller, you can just access the object in the controller:
App.UsersNewView = Ember.View.extend({
didInsertElement: function() {
this.$('input:first').focus();
},
create: function(){
console.log('view submitted');
var newUser = this.get("controller.content");
console.log(newUser.get("name_first"));
console.log(newUser.get("name_last"));
// HOW DO I PROCESS THIS FORM
}
});
Note: As i am writing this i am realizing that it would be probably better, if you would handle this event in your Controller instead of the View, since its an data modification task.

Ember.js: Passing model into view

I have a controller with data about user accounts (icon, name, provider, etc.). Within the output of the each loop I have a view that will build a CSS class dynamically based on the provider passed in via that specific model.
<script type="text/x-handlebars" data-template-name="accountItem">
{{#each account in controller}}
{{#view App.AccountView}}
<h4>{{account.name}}</h3>
<img {{bindAttr src="account.icon"}} />
<i {{bindAttr class="account.provider"}}></i>
{{/view}}
{{/each}}
</script>
App.AccountView = Ember.View.extend({
tagName: 'a',
classNames: ['avatar-image'],
providerClass: function(el) {
// do something
}
});
The question I have is two-fold.
How do you pass in "account", or the currently iterated item, into the view?
After you pass it in, how do you reference it?
I'm sure this is something that happens quite often but I can't seem to find any examples. Can anyone offer some input on this please?
Views has a special content property in a view which allows a more simple approach: you just use a name of the model's property without the view.content. part.
Also, when you're iterating over controller, you can omit the name of loop variable and use this instead, like in this guide. This is not necessary but can make the code a bit cleaner.
Also, from within view's template you generally don't need to reference the outside variables although you can if you like..
{{#each controller}}
{{#view App.IndexView contentBinding="this"}}
<h4>{{name}}</h4>
<img {{bindAttr src="icon"}} />
<i {{bindAttr class="provider"}}></i>
<i> {{icon}} </i>
<i>{{provider}}</i>
{{/view}}
{{/each}}
And you can always access the content property from within the view with:
this.get('content');
The currently iterated item can be passed into the view with the help of property bindings and it can be refered as "{{view.property}}" in the template. For example:
{{#each account in controller}}
{{#view App.IndexView itemBinding="account"}}
<h4>{{view.item.name}}</h3>
<img {{bindAttr src="account.icon"}} />
<i {{bindAttr class="account.provider"}}></i>
<i> {{view.item.icon}} </i>
<i>{{view.item.provider}}</i>
{{/view}}
{{/each}}
I have created a simple jsfiddle for the above case. Do check it and let me know if you were able to resolve the issues.
Fiddle url : http://jsfiddle.net/nCyn6/3/

emberjs #each helper not producing any output even though the template was rendered

Though the "posts/index" template is rendering, the emberjs #each helper inside the template does not produce any output. this is the jsfiddle: http://jsfiddle.net/rxWzu/
I have tried this:
{{#each post in content}}
<p> {{post.title}} </p>
<p>{{#linkTo 'posts.post' post}} {{post.body}} {{/linkTo}}</p>
{{/each}}
and this
{{#each controller}}
<p>{{title}} </p>
<p>{{#linkTo 'posts.post' post}} {{body}} {{/linkTo}}</p>
{{/each}}
Thanks.
You should use EmBlog.Post.find() in your model method for EmBlog.PostsIndexRoute.
EmBlog.PostsIndexRoute = Ember.Route.extend({
model: function(){
return EmBlog.Post.find();
}
...
Also, you don't need to call setupController in either of your routes. The way you called it is the default in Ember.
JSFiddle example