I have a base class which has some properties. I'm inheriting this class into two other controllers. Whenever I set a content to this variable, though, the content is shared between the two controllers. I don't this to happen, otherwise I'd have used Mixins. I want to set the content in one child to something and when I go to the other route, the content is still blank.
// base controller
export default Ember.Controller.extend({
method: null,
actions: {
changeMethod() {
this.set('method', 'content is shared');
}
}
}
// children.js
import BaseClass from './base-class';
export default BaseClass.extend({ //code here });
// child1.hbs
{{method}} - it shows the same as child2.hbs
// child2.hbs
{{method}} - it shows the same as child1.hbs
Ok, what I had to do is the same as they recommend for Mixins: I've created a init() method setting the variables to the default value. In the example I gave it became:
export default Ember.Controller.extend({
method: null,
init() {
this._super():
this.set('method', null);
},
actions: {
changeMethod() {
this.set('method', 'content is shared');
}
}
}
The objects created share the same prototype. According to Mozilla:
Changes to the Object prototype object are seen by all objects through prototype chaining, unless the properties and methods subject to those changes are overridden further along the prototype chain. This provides a very powerful although potentially dangerous mechanism to override or extend object behavior.
More into this topic can be seen here
There are two ways to avoid the sharing behavior.
Use computed properties
Initializing on the init function, as I did
More reference in the subject here as #lock said
Related
I have a bunch of data-only "classes" (in .NET world we call them POCO objects) that does not have any methods or even constructors. Examples are Customer, Product, User entities, you name it...
Originally I started using typescript classes but now I'm thinking that declaring them as interface might be better. From performance standpoint, and not only... It's just that in C# we're used to use interfaces for different thing, and for "POCO" (Plain-old-clr-object, or "data-only" object) we use just a class (sometimes even struct).
What is a proper way to declare them in TypeScript?
Note that I mostly understand (I think) technical differences between class and interface (i.e. that interface is a compile-time construct), but I'm trying to find out which one fits this case semantically.
P.S.: I've seen similar questions (like this) but none of them adress this specific issue clearly and definitely, so please don't close this as 'possible duplicate' or 'opinion-based' (cause it isn't) :)
Interface and it's not even close.
People start writing TypeScript and they suddenly think they have to use classes for some reason. But they don't. Classes are an ES6 feature and they work fine, but if it's just data, it's just data.
A major problem with using classes is that they won't serialize/deserialize like you expect over the wire, so things like instanceof checks won't work.
One rule of thumb is that if there's not internal state associated with some methods, and there's no need for traditional OO polymorphism, don't use a class. This even extends to static classes -- use namespace / module instead.
Use classes with parameter properties:
// Immutable data object
class Person {
constructor(readonly firstName: String, readonly lastName: String) {}
}
// Mutable data object
class Person {
constructor(public firstName: String, public lastName: String) {}
}
I use classes for my data in Typescript, as I allways did in C# C++ Java, and only use interfaces for dependency injection. Interfaces have not be thought for manipulating data.
In my application model, if I need to write a method that uses some datas of the same class, then the class is better place to go for that method. Adding getters and setters that transform your properties is a great flexibility.
I am not a javascript programmer so when I need to create an object, I don't like using data only object where properties can by anything. I create an instance of class by the way of the constructors that have been defined for that class.
When I receive data from a service, I don't deserialize a class: I deserialize the json data and I create my instance with that data. Here is the way for building my model from the received data:
// ajax callback for diaries
onReceiveDiary( jsonDiary : any )
{
let newDiary = new Diary ( jsonDiary );
// now I can call methods on the object:
let ok : boolean = newDiary.CheckIfCompleted();
}
In the class I add a constructor with the only one dependency on the json object:
export class Diary
{
title : string;
article : Article;
constructor( json : any )
{
// the trick for setting all the object properties
$.extend( this, json);
this.article = new Article( json.article );
}
}
Or we can create a factory for building objects using the default constructor:
let newDiary = new Diary ();
$.extend( newDiary, jsonDiary );
newDiary.article = $.extend( new Article(), jsonDiary.article );
Say I have a custom component as my-panel
And in the backing JS (my-panel.js)
this.get('targetObject')
Also I reference/use this component from another custom component say my-sections.hbs as
{{my-panel}}
My question is when I do
this.get('targetObject') //Called inside my-panel.js
How/Where does it lookup the property targetObject in ? What does the chain look like?
It looks it up within the scope of the backing custom component js (probably).
The chain/scope really starts from the this object, so depending what this is in that scope, that's really where it is looking it up on. If you had a reference to a different object, or were within a callback function my statement may not be true.
App.MyCompComponent = Ember.Component.extend({
foo: 'bar',
actions: {
doit: function(){
// `this` is the scope of an instance of this component.
alert(this.get('foo'));
}
}
});
http://emberjs.jsbin.com/totibidohe/edit?html,js,output
You can think of it outside the scope of being in the template as well, and just create an instance and reference that instance and it would be the same.
var MyCompComponent = Ember.Component.extend({
foo: 'bar',
actions: {
doit: function(){
alert(this.get('foo'));
}
}
});
var j = MyCompComponent.create();
alert(j.get('foo'));
http://emberjs.jsbin.com/xekohoguto/1/edit?html,js,output
I have a very simple extension in Ext JS from Ext.form.Panel:
Ext.define('path.to.SomeClass', {
extend : 'Ext.form.panel',
xtype : 'some-class'
config : {
hasDog : true
},
constructor : function (config) {
if (this.config.hasDog) {
// do something dog related
} else {
// do something not dog related
}
}
});
I then have a "container" for this custom componet:
Ext.define('path.to.OtherClass', {
extend : 'Ext.window.Window',
// ....
items : [{
xtype : 'some-class',
hasDog : false
}]
});
However, for some reason unknown to me, the if...else evaluation in SomeClass is always picking up the default configuration for hasDog. Am I not correctly configuring some-class in OtherClass's items config?
To add a bit more context, OtherClass is called via some using code:
var window = Ext.create('path.to.OtherClass');
window.show();
From what I can see, the above is pretty standard stuff - at least in thought.
The reason why you always get the default configuration is because you're accessing this.config, which is the declaration of your configuration, instead of the actual configuration from the constructor argument. So either use config or - once you've called the parent class constructor - this.
constructor : function (config) {
// before parent class constructor or this.initConfig was called:
console.log(config.hasDog);
// call parent class constructor
this.callParent(arguments);
// after parent class constructor or this.initConfig was called:
console.log(this.hasDog);
}
Also have a look at the documentation:
Note: You need to make sure Ext.Base.initConfig is called from your constructor if you are defining your own class or singleton, unless you are extending a Component. Otherwise the generated getter and setter methods will not be initialized.
In your case, since your extending a component, calling the parent constructor should suffice (as shown in the example above).
I've spent a lot of time debugging strage error in my component. That component have disabled/enabled buttons, but I haven't seen the effect. After a while, I've noticed, the buttons are changed in the last component instance I've created. The declaration looks so:
constructor: function(options) {
for(var i in options){
this[i] = options[i];
}
},
domNode: null,
grid: null,
data: [],
buttons: {},
In the debug, I've seen, that when I create second instance of my object:
new CustomComponent({domNode: dojo.byId('secondid')})
the buttons are already set - their instance is shared by all instances!
In end effect, I've created a static variable in my component. This is not what I wanted! What is wrong in that declaration? How should I made 'buttons' instance separate for each component instance?
I suppose that CustomComponent is a widget? Then you're doing some stuff wrong. The thing you do in your constructor (I suppose that's to populate your widget properties?) is not even necessary since that's already there by default when you use dijit/_WidgetBase.
Same with your property domNode, it's also there already by default if you use dijit/_WidgetBase.
My guess is that by overriding the constructor to act like this, you're actually doing some steps that the WidgetBase should do and thus messing up the private scope of the properties.
An example widget:
var CustomComponent = declare("my/CustomComponent", [WidgetBase], {
grid: null,
data: [],
buttons: {}
});
This code does exactly the same as your widget and is a lot shorter.
An example JSFiddle that has instance scoped properties (as you can see in the console log).
I've inspected the problem more exact. The problem is, that the declare block is executed only once, therefore creating object prototype, which values are copied to instances.
So when I do buttons: {}, I create Object, which is then copied to all children. In end effect, all children have the same buttons instance - I've created a quasi-static field.
All bugs where gone when I've created the object in the constructor:
constructor: function(options) {
for(var i in options){
this[i] = options[i];
}
this.buttons = {}
this.data = []
},
Now every instance of my component have own buttons object.
In fact, my problem was exactly described here:
dojo.declare("my.classes.bar", my.classes.foo, {
someData: [1, 2, 3, 4], // doesn't do what I want: ends up being
I am having a hard time overriding a constructor from a singleton class in ExtJS 4.1. I have an override defined, but by the time my override statement gets processed, the constructor has already executed.
Ext.define('singleton', {
singleton: true,
constructor: function() {
alert('replace me');
}
});
Overriding the constructor of a singleton doesn't make sense, a singleton is a class that is very early on in the execution of Extjs turned into an instance of itself. This means that you are trying to override an instance of a class and not the class itself.
I can recommend that whatever you want done to the singleton be done in a separate method in the class definition that you can call very early in Ext.onReady() or your apps instantiation.
You can't override a singleton class, that is true, but you can override the singleton instance:
Ext.define('singleton', {
singleton: true,
constructor: function() {
// does whatever
}
});
Ext.define('singletonOverride', {
override: 'singleton',
// adding new property
foo: 'bar',
// adding new method
baz: function() {},
initSingletonOverride: function() {
// do whatever is needed
// to augment the singleton
// behavior the way you want
}
},
function() {
// `this` is the singleton instance
this.initSingletonOverride();
});
Keep in mind that all this fluff comes down to the JavaScript objects. A class is an Object, and a class instance is another Object. You can override either of them, or both; the class system is here to help you not to lose track of what you're doing.