Ember JS - view insertion event - ember.js

I have the following Handlebars template which contains some views that are being output in an #each.
<script type="text/x-handlebars" data-template-name="thread">
{{#view My.ContainerView}}
{{#each message in messages}}
{{view My.MessageView contentBinding="message"}}
{{/each}}
{{/view}}
</script>
I am using the didInsertElement event to catch the insertion of the parent view.
I know there is didInsertElement fired on insertion of each My.MessageView but what I was wondering was if there was an event fired when all of the My.MessageViews were inserted? Meaning the #each is finished. Maybe there is a similar event for a view being fully rendered?
// Ember Noobie

I've run into a similar scenario, in regards to where to fire a jquery event after child views have rendered. With some help from this forum, I ended up with something like this:
The view below is rendered once for each item that I ajax in (for a bootstrap accordion).
App.AccItemView = Em.View.extend
classNames: ['accordion-group']
templateName: 'acc_item'
didInsertElement: ->
Ember.run.next this, ->
#.$('.collapse').collapse({parent:"#accordion2"})
There's also an afterRender hook, which I'm still experimenting with myself.
didInsertElement: ->
Ember.run.scheduleOnce 'afterRender', this, () ->
#.$('.collapse').collapse({ parent:'#accordion2'})
A fiddle is here, if it is of any use.
http://jsfiddle.net/nrionfx/s59fA/16/

Related

Evaluating controller property everytime the template is rendered in Ember

I have a template called sample and I am changing the property show in the controller based on a button press. Now I want the controller to reset the property every time the template is rendered. Currently even if I go to 'next' template and come back, the property show remains true if the button on sample was pressed. I want to change this behaviour and the property show should be false by default. I know I can do this by defining a view and using the didInsertElement hook but is that the only way to do this?? Ember.js website says that Views in Ember.js are typically only created for the following reasons:
When you need sophisticated handling of user events
When you want to create a re-usable component
and I am doing none of the above. Here is some sample code:
<script type="text/x-handlebars" data-template-name="sample">
{{#if show}}
Showing stuff
{{/if}}
<button {{action changeShow}}>Change</button>
{{#link-to 'next'}} Next {{/link-to}}
</script>
<script type="text/x-handlebars" data-template-name="next">
Hello
{{#link-to 'sample'}}Back{{/link-to}}
</script>
App.SampleController=Ember.Controllers.Extend{(
show:false,
actions:{
changeShow:function(){
this.controllerFor('sample').set('show',true);
}
}
)};
you can use didTransition action which will trigger automatically once the transition happened. didTransition action
App.SampleController=Ember.Controllers.Extend{(
show:false,
actions:{
didTransition:function(){
this.controllerFor('sample').set('show',false);
},
changeShow:function(){
this.controllerFor('sample').set('show',true);
}
}
)};
You can use the renderTemplate hook for the route you're doing this in, and change the controller variable in there.
http://emberjs.com/api/classes/Ember.Route.html#method_renderTemplate
I'd do something like this:
App.PostsRoute = Ember.Route.extend({
renderTemplate: function(controller, model) {
var favController = this.controllerFor('favoritePost');
favController.set("toggle", false)
this._super()
}
});

Ember partial onload

I'm trying to draw a timeline when the timeline route is opened. Currently have and it partially works, i.e. if you refresh the timeline page, but navigating to timeline page will not draw timeline. I was wondering if it is possible to do {{partial onload="drawTimeline}} or something along those lines.
I've also tried making a handlebars helper {{drawTimeline}} and calling that when partial is loaded, but it is getting an undefined value.
EDIT:
kingpin2k's fix worked for me. This is what I did:
HTML:
{{#view Blocks.Timeline}}
<div id="mytimeline"></div>
{{/view}}
JS:
Blocks.Timeline = Em.View.extend({
didInsertElement : function(){
drawVisualization();
}
});
Is drawTimeline a function on the controller of the current route?
If so, create an associated view and hook up to the didInsertElement and run the function there.
App.SomethingView = Em.View.extend({
didInsertElement : function(){
// do it here
}
});

Access Controller in a View in a Render

I have a view like this:
App.AbilityFilter = Ember.TextField.extend({
classNames: ['span3'],
keyUp: function(evt) {
this.get('controller').send('filterAbilities','text');
},
placeholder:'Search abilities'
});
It's part of a render like this:
<script type="text/x-handlebars" data-template-name="abilities">
{{view App.AbilityFilter}}
<div class="accordion" id="abilities">
{{#each ability in model}}
<div class="accordion-group">
{{ability.name}}
</div>
{{/each}}
</div>
</script>
Which is being rendered in my application like this:
{{render 'abilities'}}
The problem I'm having is with the event or, rather, the action. The keyUp event fires perfectly well, but for some reason it won't go to a controller.
I've tried adding the filterAbilities to the actions hash on both the App.AbilitiesController and the App.IndexRoute according to this. According to this, the view should be part of the abilities controller since that's the context of it's parent, but it's not working.
I've done some testing and it almost seems like this.get('controller') isn't fetching a controller at all. I'm a bit lost as to what's causing the problem. This code worked a few RCs ago, but as soon as I upgraded to 1.0 it broke.
What I'm trying to do here is filter the list of abilities. If this isn't the way to this anymore, please let me know! Any help would be appreciated. Thanks!!
Ember.TextField and Ember.TextArea are no longer simple views but rather subclasses of Ember.Component which means that this.get('controller') does not refer anymore to the views controller.
But there is a different variable which indeed holds a reference to the surrounding controller and this is this.get('targetObject'). Therefore you should send your action to the targetObject:
App.AbilityFilter = Ember.TextField.extend({
classNames: ['span3'],
keyUp: function(evt) {
this.get('targetObject').send('filterAbilities','text');
},
placeholder:'Search abilities'
});
Hope it helps.

toastr and ember.js

Is the popup library toastr not going to work with Ember because of direct dom manipulation that ember doesn't like?
Are there any other libraries like this one that work nicely with ember?
Edit
Even through the working example posted below I could not get this to work locally. I finally used Pine Notify which worked straight away.
This works fine in Ember, you just have to handle the event in the right place. The "right place" depends on your implementation. If you want this to be fired from a button within your view, you'll need to use the {{action}} helper passing the action name. Example:
<script type="text/x-handlebars" >
<button class="btn btn-info" {{action showInfo}}>Info</button>
</script>
In the template above, I'm saying that the button should fire the showInfo event, so the Controller responsible for this view should have a function with the same name:
App.ApplicationController = Em.ArrayController.extend({
showInfo: function() {
toastr.info('This is some sample information');
}
});
You can also have the view handle the event; the code below defines a click event, so if you click anywhere in the view, it would run your function:
App.OtherView = Em.View.extend({
click: function(e) {
toastr.error('This is some sample error');
}
});
and in your Handlebars template, you don't have do tell the action since you are already saying in the view class that you want to handle the click event for that view, so you can simple render the view and style it:
{{#view App.OtherView class="btn btn-danger"}}
Error
{{/view}}
Here's a sample in JSFiddle: http://jsfiddle.net/schawaska/YZwDh/
I recommend that you read the Ember Guide about the {{action}} helper

Emberjs + Handlebars + Object onchange and events

I'm finding that jQuery observers aren't bound to elements that are not shown in handlebars logic.
Let's say I have the following;
{{#if person}}
Welcome back, <b>{{person.firstName}} {{person.lastName}}</b>!
{{else}}
Please <a class="login">log in</a>.
{{/if}}
<script>
$('.login').click(function() {
alert("Hi there.");
});
</script>
If I run in console, person = null (or whatever's needed to convince that person is empty) - the login observer doesn't work. I'm already using embers didInsertElement() to load a few other things, but is there a "onChange" event I can hook into so I can rebind event observers?
The big question is why you want that? Ember has excellent built in support for click handlers without going via jQuery. The reason your <script> is not working is likely to be down to the deferred way ember inserts views into the DOM. When you do Ember.View.append() the element is inserted in the DOM later.
That said, here's a fiddle that does what I think you want attaching the jQuery click handler in didInsertElement().
http://jsfiddle.net/algesten/5LPPz/1/
didInsertElement: function () {
// appending click handler directly with jQuery
$('.login').click(function() {
alert("Hi there.");
});
}
However the ember way would be to just use the click implicit handler function:
http://jsfiddle.net/algesten/5LPPz/2/
click: function () {
alert("Hi there.");
}
N.B. the latter handler attaches to the surrounding handlebar div and not the a, but clicks bubble.
The problem your facing is that javascript can only bind to elements that exist in the dom. Once you add a new element it wants you to re-bind those events. Luckily, jQuery is your friend on this one.
<script>
$('body').on('click', '.login', function() {
alert("Hi there.");
});
</script>
Ideally, your selector is the closest parent to .login that doesn't get added by javascript. The above is safe bet if you're not sure