i have an ember view with a bunch of jquery code to manipulate the dom, the thing is when i use:
this.transitionTo("forecast.workpage", id);
it only loads the view once but when i try click it again the view doesn't execute again, i try several ways for instance adding this.rerender() in the end of my didInsertElement like that:
didInsertElement : function(){
//all my js code
this.rerender()
}
but it trows an error
Uncaught TypeError: Cannot read property '0' of undefined
, try adding this._super() in the begin, same result, is there a way to force the view to refresh from the view itself or the route? or controller ?
edit: try this approach with no results...
didInsertElement : function(){
this._super();
Ember.run.scheduleOnce('afterRender', this, this.afterRenderEvent);
},
afterRenderEvent: function(){
//$(document).foundation();
$(".sortables li:even").find('div.row').addClass("gray");
}
Same thing, executes onces but where i click on the action doesn't execute the code.
To re-render the whole route (page), you can use the route's refresh method. Or, as a possible solution to this.rerender() failing, you could call that after it renders the first time.
didInsertElement: function() {
Ember.run.scheduleOnce('afterRender', this, function() {
this.rerender();
});
}
Personally, I wouldn't recommend either one. Your view should update automatically when the data it depends on changes. It if it's not updating, you probably have your observers set up wrong. (I don't really know your use case though, so use your best judgement.)
Related
Is there any event fired stating the transition/rendering has completed (and the dom is visible/ready).
setupcontroller/activate are before the dom is built/rendered
didInsertElement gets fired only the first time when I've already inserted an element and I'm just switching the model out underneath it.
What I'm really looking for is the transition is complete event
I guess I can do this, but I was kind of hoping it was already built in...
Ember.Router.reopen({
didTransition:function(infos) {
this._super(infos);
console.log('transition complete');
}
});
Even cooler would be a callback to the route that the transition completed for it, I may have to write this and submit a pull request.
There are a couple of different ways you can solve this
didInsertElement
This is fired when the view is inserted on the first time, but not fired if the model is switched out under the view (because Ember likes to reuse items, since it's cheaper than rebuilding the entire DOM). Example below.
Simple
If you only need to do it once, the first time the view is inserted, use didInsertElement
App.FooView = Em.View.extend({
setupSomething: function(){
console.log('the dom is in place, manipulate');
}.on('didInsertElement')
});
Example: http://emberjs.jsbin.com/wuxemo/1/edit
Complex
If you need to schedule something after the DOM has been rendered from the route itself, you can use schedule and insert it into the afterRender queue.
App.FooRoute = Em.Route.extend({
setupController: function(controller, model){
this._super('controller', model);
Ember.run.schedule('afterRender', this, function () {
//Do it here
});
}
});
Example: http://emberjs.jsbin.com/wuxemo/2/edit
Transition promise
The transition's promise will complete before it's finished rendering items. But it gives you a hook for when it's done with fetching all of the models and controllers and hooking them up.
If you want to hook up to the transition event you can do it like so:
var self = this;
transitionTo('foo').then(function(){
Ember.run.schedule('afterRender', self, function () {
//Do it here
});
})
The afterModel hook might work for you:
App.MyRoute = Ember.Route.extend({
afterModel: function(model, transition) {
transition.then(function() {
// Done transitioning
});
}
});
I tested this using RC-7 with routes that both do and don't have dynamic segments (i.e., a route with a model and a route without a model). It seems to work either way.
See this JSBin for an RC-6 example:
Output: http://jsbin.com/OteC/1/
Source: http://jsbin.com/OteC/1/edit?html,js
setupController is the last thing that the Router calls before finalizing the transition. And if it completes without errors, as far as Ember is concerned the transition is complete. You actually see this in action by enabling LOG_TRANSITIONS_INTERNAL.
At that point, It doesn't matter if the controller has thrown an error, view has thrown an error, etc. The router has completed transitioning into the target route.
So setupController is the last place in terms of the Router that corresponds to didTransition.
When the content/model backing the controller changes on an existing View, the bindings kick in. Most of the changes that happen to the view at that point are via Metamorphing.
The closest place I can think of to hook into would be View.render which pushes changes into the RenderBuffer. But you still need to account for Metamorphing via mixins that happens here.
didTransition does exist as you hoped -- but its an action and not a hook
XXRouter
actions: {
didTransition: function() {
this.controller.set("hasTransitioned", true); // or whatever is needed?!
return true; // Bubble the didTransition event
},
}
XXController
observeTransition: function() {
alert('complete Transition');
}.observes('hasTransitioned'),
I am getting a basic feel for Ember, and running into some weird issues at the moment. The app is pretty basic (and ugly). On a specific route, (/stack) , I list out a bunch of cards that belong to this stack. StackController is an array controller since it retrieves a stack of cards that belong to it, essentially
StackController = Ember.ArrayController.extend();
and
StackRoute = Ember.Route.extend({
model: function(){
return App.Card.find();
}
});
Then in my templates, I simply loop through it using the #each helper to display a property of the card ('front'), like this:
<ul>
{{#each}}
<li>{{front}}</li> <button {{action 'backside' this}}>View</button>
{{/each}}
</ul>
Up until here, everything is working the way it should. However, when I click on the 'View' button to trigger the 'backside' event, it yields a :
"Nothing handled the event 'backside' " error. Kind of bummed because it seems pretty basic that it should do so, oh yes, I do explicitly specify the 'backside' event in my Controller, like this:
StackController = Ember.ArrayController.extend({
actions:{
backside:function(){
alert("backside event handled");
}
}
});
For a more detailed look, here is the jsBin:
http://jsbin.com/AHiTicU/5/edit
What am I doing wrong?
The code in the JSBIN is accurate, there maybe some typos here however (unlikely, but a heads up).
You are using the ember-1.0.0-rc.6, in that version to use the action you need to put you action handler inside of the route, in a object with a key called events, like the following:
App.StackRoute = Ember.Route.extend({
model: function(){
return App.Card.find(); // must substitute this with this.store.find('card');
},
events:{
backside:function(){
alert('working');
}
}
});
Updated jsbin http://jsbin.com/AHiTicU/6/edit
I recommend you to use the lastest version, at the moment 1.2.0, you can get it in the home page of emberjs website http://emberjs.com/.
So your current code will work http://jsbin.com/AHiTicU/9/edit
I rarely get stuck in JS but this time I have a feeling I did something wrong somewhere - Enlightened people, here you go :
in view1, I have :
listView = new ListView({collection: listElements});
listView.render();
Which is called each time listElements changes.
in ListView, the collection gets parsed to a template in the render method then an event is fired on click :
//ListView.js
events: {
"click .listEl": "doStuff"
...
},
doStuff: function(e) {
// if this is when the problem arises : this.collection at this place isn't the
// same collection passed to ListView in view1 (or the collection in
// the initialize() ).
// It's actually the first value ever to be rendered with ListElements.
Any thoughts ?
Thanks #muistooshort for the head's up.
It was due to Zombie events/views; to 'quickly' fix it, run this after you need to get rid of the view and it's bound to events.
this.listView.undelegateEvents();
$(this.listView.el).removeData().unbind();
this.listView.$el.html('');
A more elegant version would be to extend Backbone.View and add a remove() method to it.
Is there any event fired stating the transition/rendering has completed (and the dom is visible/ready).
setupcontroller/activate are before the dom is built/rendered
didInsertElement gets fired only the first time when I've already inserted an element and I'm just switching the model out underneath it.
What I'm really looking for is the transition is complete event
I guess I can do this, but I was kind of hoping it was already built in...
Ember.Router.reopen({
didTransition:function(infos) {
this._super(infos);
console.log('transition complete');
}
});
Even cooler would be a callback to the route that the transition completed for it, I may have to write this and submit a pull request.
There are a couple of different ways you can solve this
didInsertElement
This is fired when the view is inserted on the first time, but not fired if the model is switched out under the view (because Ember likes to reuse items, since it's cheaper than rebuilding the entire DOM). Example below.
Simple
If you only need to do it once, the first time the view is inserted, use didInsertElement
App.FooView = Em.View.extend({
setupSomething: function(){
console.log('the dom is in place, manipulate');
}.on('didInsertElement')
});
Example: http://emberjs.jsbin.com/wuxemo/1/edit
Complex
If you need to schedule something after the DOM has been rendered from the route itself, you can use schedule and insert it into the afterRender queue.
App.FooRoute = Em.Route.extend({
setupController: function(controller, model){
this._super('controller', model);
Ember.run.schedule('afterRender', this, function () {
//Do it here
});
}
});
Example: http://emberjs.jsbin.com/wuxemo/2/edit
Transition promise
The transition's promise will complete before it's finished rendering items. But it gives you a hook for when it's done with fetching all of the models and controllers and hooking them up.
If you want to hook up to the transition event you can do it like so:
var self = this;
transitionTo('foo').then(function(){
Ember.run.schedule('afterRender', self, function () {
//Do it here
});
})
The afterModel hook might work for you:
App.MyRoute = Ember.Route.extend({
afterModel: function(model, transition) {
transition.then(function() {
// Done transitioning
});
}
});
I tested this using RC-7 with routes that both do and don't have dynamic segments (i.e., a route with a model and a route without a model). It seems to work either way.
See this JSBin for an RC-6 example:
Output: http://jsbin.com/OteC/1/
Source: http://jsbin.com/OteC/1/edit?html,js
setupController is the last thing that the Router calls before finalizing the transition. And if it completes without errors, as far as Ember is concerned the transition is complete. You actually see this in action by enabling LOG_TRANSITIONS_INTERNAL.
At that point, It doesn't matter if the controller has thrown an error, view has thrown an error, etc. The router has completed transitioning into the target route.
So setupController is the last place in terms of the Router that corresponds to didTransition.
When the content/model backing the controller changes on an existing View, the bindings kick in. Most of the changes that happen to the view at that point are via Metamorphing.
The closest place I can think of to hook into would be View.render which pushes changes into the RenderBuffer. But you still need to account for Metamorphing via mixins that happens here.
didTransition does exist as you hoped -- but its an action and not a hook
XXRouter
actions: {
didTransition: function() {
this.controller.set("hasTransitioned", true); // or whatever is needed?!
return true; // Bubble the didTransition event
},
}
XXController
observeTransition: function() {
alert('complete Transition');
}.observes('hasTransitioned'),
I am using Ember.js in my application, but there is a point where I update a property of the view's context(controller) but right after the update there is a parser(MathJax) that looks at the dom for the updated fields to parse it into math. However even though the update is taking place, it happens after mathjax looks for the update. What I need to do is force ember to update the view or wait for ember to update before I tell mathjax to parse the html. Is there a way to achieve this?
This is a fairly common use-case. To specify code that should execute after a property's changes have propogated, use an observer. Ember triggers observers after it successfully propagates the change. For example:
App.MathView = Ember.View.extend({
controller: null,
template: Ember.Handlebars.compile("<div>{{myProperty}}</div>"),
myPropertyDidChange: function() {
// From here the controller value is changed but DOM has not been updated
Ember.run.next(this, function() {
// This code will run when after changes have propagated to the DOM
// Call MathJax parser here
// If needed you can access the view's DOM element via this.$()
alert("New property value is in dom: "+ this.$().text());
});
}.observes('controller.myProperty')
});
See the Ember Managing-Asynchrony Guide and API docs for Ember.run:
http://emberjs.com/guides/understanding-ember/managing-asynchrony/
http://emberjs.com/api/classes/Ember.run.html#method_next