this._super() issue when an object is created - ember.js

In the new EmberRC1 version, it seems that we cannot call super class method from a created object. I have some standard mixins and views which i use to either create or extend to some other objects. I have some methods overriden, but still i needed to execute super methods which we can acheive in previous versions using this._super(). But in the newer version, when i create an object, this is not happening.
window.App = Ember.Application.create();
App.Router.map(function(){
this.resource("users");
});
App.UsersView = Ember.ContainerView.extend({
init : function(){
this._super();
this.pushObject(App.TestView.create({
didInsertElement : function() {
this.$().append(' <br><h4>Appended at Object</h4> ');
}
}))
}
});
App.TestView=Ember.View.extend({
templateName:'test',
didInsertElement : function() {
this.$().append(' <br><h4>Appended at Class</h4> ');
}
});
So is this part completely removed or we can acheive this super calling some other way?
To understand my problem here is the jsfiddle.
PS: I know that i can have the code that needs to be executed with some other methodname and call the same method. But it would be nice if i have solution for this.

You can still call this._super() from an init method and it will call the parent. What has been removed is calling create on an object and passing in an init method. There is a createWithMixin method that still allows that functionality.
There is a pretty detailed post about this functionality here:
Difference between .create() and .createWithMixins() in ember

Related

Can't set controller's content when async action in EmberJS

I'm getting stuck when I want to update my controller's content after a specific action :
this.set('content', CL.myModel.findALL());
I'm not using ember-data or any of them.
CL.myModel.findALL returns an Ember promise that returns itself the result in it's callback.
Actually, I've done the same thing in my setupController in the router and It works well.
Why does it not work in the controller itself ?
Thank you for helping.
You should do:
controller = this;
CL.myModle.findALL().then(function(models) {
controller.set('content', models);
})
I believe the reason that it works without this in Route#setupController is because, behind the scenes, Ember does something similar to the above code with the result of your model hook (which is typically a promise).
Another option you could look at is DS.PromiseObject (it's a nice abstraction for promises that wrap a promise and expose it's fulfillment value as content. You'd have to extract it from an ember-data build though.
Here is an example of my model :
CL.myModle.reopenClass({
findAll : function(){
return CL.Utils.ajaxPromise(r)
.then(this.findByIdSuccess.bind(this), this.findByIdFailed.bind(this));
},
findByIdSuccess: function (data) {
var negotiation = CL.NegotiationModel.create(data);
this.setMembers(negotiation);
this.setParties(negotiation);
this.setVersions(negotiation);
return negotiation;
},
})
Here is my controller :
onRefresh : function(){
this.set('content',CL.myModle.findAll())
}
As you can see in the model part I call some functions that do some model modification and I get it back findByIdSuccess callback.
I can't just return the datas I retrieve in the "then" of the promise.
My question again if it's still not clear : Is there any way to get the promise's data without doing :
CL.myModle.findALL().then(function(models) {
controller.set('content', models);
})

Call custom function when view is rendered, from one place and not repeating code for every view

in ember application i want to call my custom function which does some modifications of dom elements, the only solution i found is to repeat below code as many times as many views/routes i have
for example
rendering indexView
indexView = Ember.View.Extend({
didInsertElement:function(){
//my custom function call goes here.. myFunction();
}
});
rendering OtherView
OtherView = Ember.View.Extend({
didInsertElement:function(){
//my custom function call goes here.. myFunction();
}
});
rendering MoreView
MoreView = Ember.View.Extend({
didInsertElement:function(){
//my custom function call goes here.. myFunction();
}
});
Is there a way of calling myfunction globaly whenever any view is rendered? I really do not want to repeat code for every single view i render.
thanks!
You can create a Mixin:
App.SomeMixin = Ember.Mixin.create({
didInsertElement: function() {
this._super();
//do your common stuff here
}
});
And use it in your views:
App.SomeView = Ember.View.Extend(App.SomeMixin, {
didInsertElement: function() {
this._super();
//do your custom stuff here
}
});
I would use a mixin to do this. If, however, you find that you are using this mixin into every single view that you create, it might be better to reopen the Ember.View class and add this functionality there. Also,if you reopened the class, what you could do is, depending upon the use case, create a static function inside Ember.View.reopenClass which you would pass to a
Ember.run.scheduleOnce()
utility that ember provides so that, if the function that you need doesn't need any state (for example, just does something to the page after the content has loaded or something.), it will just run the function once after all the views are rendered in the page.
There are two ways to handle this. Create a base class, or reopen the global View class and insert your code. I prefer the first, since it's easier to maintain and track down issues.
Reopen the View class and tack on an additional method that triggers on didInsertElement
Ember.View.reopen({
doStuff:function(){
//myFunction();
}.on('didInsertElement')
});
In the case of debouncing
Ember.View.reopen({
doStuff:function(){
Ember.run.debounce(this.doRealStuff, 200);
}.on('didInsertElement'),
doRealStuff: function(){
console.log('foo');
}
});
http://emberjs.jsbin.com/gecoziwe/1/edit
Create a base class and extend from it (My preferred method, since it's easier to track down issues, can't say this enough)
App.BaseView = Ember.View.extend({
doStuff:function(){
//myFunction();
}.on('didInsertElement')
});
App.FooView = App.BaseView.extend({
});
App.BarView = App.BaseView.extend({
});

Observer not firing on created object

I am trying to use observers to observe a change on my model after XHR. This is because the earlier approach of extending a fn and calling super is not allowed any more.
Running into this weird issue where my observer doesn't fire:
App = Ember.Application.create({
ready: function () {
console.log('Ember Application ready');
this.topCampaignsController = Ember.ArrayController.create({
content: null
});
App.TopCampaignsModel.create({
// Calling super is no longer allowed in object instances
//success: function () {
// this._super();
// App.topCampaignsController.set('content', this.get('data'));
//},
onDataChange: function () {
console.log('data property on the object changed');
App.topCampaignsController.set('content', this.get('data'));
}.observes('data')
});
}
});
App.TopCampaignsModel = Ember.Object.extend({
data: null,
// this will be actually called from an XHR request
success: function () {
this.set('data', [5,10]);
},
init: function () {
console.log('TopCampaignsModel created');
this.success();
console.log(this.get('data'));
}
});
Jsfiddle here: http://jsfiddle.net/gdXfN/26/
Not sure why the console doesn't log "data property on the object changed". Open to alternative approaches on how I can override the 'success' fn in my instance.
After this commit in December last year, it is no longer possible to set observers during object creation. This resulted in a huge performance win.
To set observers on create you need to use:
var Object = Object.createWithMixins({
changed: function() {
}.observes('data')
});
Here's a fiddle demonstrating this.
The API documentation should be updated accordingly, something I will do later on.
However, I don't advise you to do that, but instead set observers during object definition. The same result can be achieved: http://jsfiddle.net/teddyzeenny/gdXfN/32/
That said, there are two things you are doing that go against Ember concepts:
You should not create controller instances yourself, you should let Ember create them for you:
App.TopCampaignsController = Em.Controller.extend({ content: null });
When the App is initialized, Ember will generate the controller for you.
Models should not be aware of controller existence. Controllers should access models not the other way round.
Models and Controllers will interact together through routes.
For the last two points, you can watch the tutorial at http://emberjs.com/guides/ to see how the Application, Controllers, Models, and Routes should interact. Since you're not using
Ember Data, just ignore DS.Model and imagine an Ember.Object instead. The tutorial can give you a pretty good overview of how objects should interact.

Best way to detect if an Ember.Object is dirty

I have an ember object and i'd like to know if it is in a dirty state.
var App.Post = Ember.Object.create({
title: "Test",
isDirty: false
});
App.Post.set("title", "Test2");
App.Post.get("isDirty") // Should === true
For the moment, I have tried overloading the set for the object
App.Post = Ember.Object.create({
set: function(path, value) {
this._super(path, value);
this._super("isDirty", true);
}
})
It works when I am calling directly myObject.set but it doesn't seem to use that set function when using embers binding. I added logs and this method isn't called by the regular emberjs bindings workflow.
Another thing I've tried is to add an observers to toggle the dirty flag.
App.Post = Ember.Object.create({
hasBeenModified: function() {
this.set("isDirty", true);
}.observes("title")
})
For a reason still unknown, when I use observes at the model level my bindings do not work anymore in the UI.
I believe you may also need to override setUnknownProperty. The UI is using Ember.set(object, key, value). If you look at the implementation
https://github.com/emberjs/ember.js/blob/master/packages/ember-metal/lib/property_set.js#L60
It doesn't call your setter, but will call setUnknownProperty if it exists.
Actually, at
https://github.com/emberjs/ember.js/blob/master/packages/ember-metal/lib/property_set.js#L52
It looks like they will call your setter if you have predefined the field in your App.Post class.

Observer are not called on create()

I have a Ember.Mixin which observes one of its properties (here bar.baz).
I've extended this Mixin and set bar.baz in the .create() parameter, but my observer is not called.
Here is my code :
App.FooMixin = Ember.Mixin.create({
barBazDidChange: function() {
console.log('barBazDidChange'); // never called
}.observes("bar.baz")
});
App.Foo = Ember.Object.extend(App.FooMixin);
App.fooObject = App.Foo.create({
bar: Ember.Object.create({
baz: "ember"
})
});​
And the associated jsfiddle : http://jsfiddle.net/aMQmn/
I could of course call the observer in the init() method like below, but I wonder if there is a better solution (or if this solution is the proper way to do that) :
App.FooMixin = Ember.Mixin.create({
init: function() {
this._super();
if (this.getPath('bar.baz')) {
this.notifyPropertyChange('bar.baz');
}
}
});
So no answer during 7days... what I would do instead of passing the property at creation time is chaining the creation and setting the property, like this:
App.fooObject = App.Foo.create().set('bar', Ember.Object.create({baz: "ember"}));​
If it's not satisfying enough, perhaps you could post an issue in the ember project on github:
https://github.com/emberjs/ember.js/issues
The correct solution is to override the init method (make sure to call this._super()) and call the function there. As others have noted, the observer is not firing because the value is not actually changing. There has been some discussion around making create behave more like setProperties which would make this a non-issue.