Dojo declare - the scope of default properties (instance or static) - javascript

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

Related

Understanding extend and method overwriting

This is a follow-up question from the previous: Why is the parent prototype method still executable after overriding?.
As we see, the literal object {metadata, aaa, init} was initialized by the extend function as a 2nd import variable, so this object should be the object automatically automatically instantiated and represents the extended sub-class. Then inside the object, it inherited the init method from its parent class and overrode it. first call the parent init method to trigger some necessary things, then setup the data for this extended component.
My question is: the init method in this literal object is its own init method, because this refered to the literal object, right? if it's yes, why I can't see it under this proprieties in my debugger tool.
enter image description here
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/model/json/JSONModel",
"sap/ui/model/resource/ResourceModel",
], function (UIComponent, JSONModel, ResourceModel) {
"use strict";
return UIComponent.extend("sap.ui.demo.walkthrough.Component", {
metadata: {
"interfaces": [
"sap.ui.core.IAsyncContentCreation",
],
"rootView": {
"viewName": "sap.ui.demo.walkthrough.view.App",
"type": "XML",
/*"async": true, // implicitly set via the sap.ui.core.IAsyncContentCreation interface*/
"id": "app",
},
},
aaa: function () {
console.log("aaa");
},
init: function () {
// call the init function of the parent
UIComponent.prototype.init.apply(this, arguments);
// set data model
var oData = {
recipient: {
name: "World",
},
};
var oModel = new JSONModel(oData);
this.setModel(oModel);
// set i18n model
var i18nModel = new ResourceModel({
bundleName: "sap.ui.demo.walkthrough.i18n.i18n",
});
this.setModel(i18nModel, "i18n");
},
});
});
Hope this other answer clears some things up:
__proto__ is the actual object that is used in the lookup chain to resolve methods, etc. prototype is the object that is used to build __proto__ when you create an object with new
This means when you see methods in the prototype section it doesn't mean that the original parent class is overwritten. Your new "class" sap.ui.demo.walkthrough.Component also has/is a prototype and this (which is an instance of your new "class") has it's own __proto__. This new prototype/proto constains methods form the parent prototype and can also define new methods.
And from the documentation of sap.ui.base.Object.extend:
Creates a subclass of class sap.ui.base.Object with name sClassName and enriches it with the information contained in oClassInfo.
oClassInfo might contain three kinds of information:
[...]
any-other-name: any other property in the oClassInfo is copied into the prototype object of the newly created class. Callers can thereby add methods or properties to all instances of the class. [...]
So when you do this.__proto you will see the build plan for the current instance.
Do this.__proto__.__proto__ to get the build plan from the parent class. Do this.__proto__.__proto__.__proto__ to get the grand parent class (and so on).
The protos of the parent class are not affected by your child class. But your child classes include everything from the parent class. When you "override" a method you are are adding a method to your new prototype. The parent method still exists in the UIComponent prototype and can therefore be called by explicitly stating UIComponent.prototype.init.apply.

Angular: How to "Save" an "Object"?

Good Morning, I explain my scenario:
After generating a couple of http calls and after processing them I have a result similar to this:
xxx.component.ts
nameVariable: any = {};
this.nameVariable = this.createMyObject(params);
console.log(this.nameVariable);
Thanks to the console.log() we can see that is an Object: nameVariable like this:
Object: {
information1: Object {...},
information2: Array [...],
information3: Object{...},
information4: Array[...]
}
How can I save this Object??,
how do I Save it and then be able to use it within the code and/or use it within a Component??
Should use a Model?? what should I study to better understand this thing??
Your angular component is a class. The scope of your nameVariable variable is the body of the method where it is defined. You can extend the scope of that variable by introducing it as a field of your class before the constructor of the class as follows:
nameVariable: { (state here the type of the object };
and you may add a prefix like private or public just before the nameVariable word.
Refer to it as this.nameVariable afterwards inside the methods (the const keyword is no more required).

Controller parent sharing content between its child

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

Ember lookup property from inside custom component

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

Backbone or JavaScript keeps model's state after constructor is called

Every time I call "this.model = new Unidade();", this.model keeps some values of the last value stored in there.
this.model.id => turns to null, but others properties keep the values of the last model.
Model Source
window.Unidade = Backbone.Model.extend({
urlRoot : $urlPadrao + "cliente/externo/unidade",
defaults: { // setting defaults to null or ""
},
initialize: function () {
... // Just initialize the validators methods
},
getDefaults: function() {
// returns the same values of defaults
// since I can't get a "new" model
}
});
In my view:
this.model = new Unidade();
// this.model may be already populated... I'm trying to create a new one
// that's the problem, it keeps some values of the last one
// Shouldn't give me a new model populate with the defaults?
For the record I'm not messing with the prototypes.
I manage to get the source of this sorcery, somehow, backbone was getting these properties and setting then on the prototype of the model, thus making them static.
Mighty strange.
By any chance are these properties arrays? I found that mine were essentially being treated as pass-by-reference due to what I found in this article :
Arrays in a Backbone.js Model are essentially static?

Categories

Resources