Related
For example, when we have 2 array properties on our component:
array: an ordinary Array
anonymousArray a subclass of Array
export class AppComponent {
readonly array = new Array<{
text: string;
value: string;
}>();
readonly anonymousArray = new class extends Array<{
text: string;
value: string;
}> {
add(text: string, value: string) {
this.push({
text,
value
});
}
}();
constructor() {
this.array.push({
text: "text1",
value: "value1"
});
this.anonymousArray.add("text", "value");
}
}
Then code-completion in the template works for the ordinary Array:
but not for the sub-class:
Here's a full Stackblitz example
IntelliJ will even show errors:
I wonder how this is possible in the first place: i.e. since Array.isArray(this.anonymousArray) is true, how/why does the template even see a difference?
Is this maybe a bug in Ivy or the angular language service?
Works fine for me in the most recent IDEA version:
Edit: appears to be specific to libraries versions being used, tracked at WEB-49995
I have this vue component:
export default {
data: function() {
return {
editor: new Editor({
//some options
}),
}
},
computed: {
doc(){ // <--------------------- take attention on this computed property
return this.editor ? this.editor.view.state.doc : null;
},
},
watch: {
doc: {
handler: function(val, OldVal){
// call some this.editor methods
},
deep: true,
immediate: true,
},
},
}
Will computed property doc be dependent on a data property editor if I use this.editor only for checking if it is defined and not use it for assigning it to the doc? I mean, If I will change this.editor will doc be changed? Also, I have watcher on doc so I need to know if I will cause an infinite loop.
In the doc property computation, you use:
the editor property (at the beginning of your ternary, this.editor ? ...)
if editor exists, the editor.view.state.doc property
So the computation of doc will be registered by Vue reactivity system as an effect related to the properties editor and (provided that editor exists) to editor.view.state.doc. In other words, the doc property will be reevaluated each time one of these two properties changes.
=> to reply to the initial question, doc will indeed depend on editor.
This can be toned though, because by 'property change', we mean:
for properties of primitive types, being reassigned with a different value
for objects, having a new reference
So, in our case, if editor, which is an object, is just mutated, and that this mutation does not concern it's property editor.view.state.doc, then doc will not be reevaluated. Here are few examples:
this.editor = { ... } // doc will be reevaluated
this.editor.name = ' ... ' // doc will NOT be reevaluated
this.editor.view.state.doc = { ... } // doc will be reevaluated
If you want to understand this under the hood, I would recommand these resources (for Vue 3):
the reactivity course on Vue Mastery (free)
this great talk and demo (building a simple Vue-like reactivity system)
About the inifinite loop, the doc watcher handler will be executed only:
if doc is reassigned with a different value
in the case where docis an object, if doc is mutated (since you applied the deep option to the doc watcher)
The only possibility to trigger an infinite loop would be to, in the doc watcher handler, mutate or give a new value to doc (or editor.view.state.doc). For example (cf #Darius answer):
watch: {
doc: {
handler: function(val, OldVal){
// we give a new ref each time this handler is executed
// so this will trigger an infinite loop
this.editor.view.state.doc = {}
},
// ...
},
}
=> to reply to the second question, apart from these edge cases, your code won't trigger a loop. For example:
watch: {
doc: {
handler: function(val, OldVal){
// even if we mutate the editor object, this will NOT trigger a loop
this.editor.docsList = []
},
// ...
},
}
Changing editor variable should work, but changing Editor content may not, as it depends on Editor class and how it respects reactivity.
For example:
export default {
data: function() {
return {
editor: {text: '' }
}
}
}
...
this.editor.text = 'Text' // works
this.editor.text = {param: ''} // works
this.editor.text.param = 'value' // works
this.editor.param = {} // does't work, as creation of new property is not observable
If editor observer works and you are changing editor property in observer, which 'reinitializes' internal structures, it may lead to infinite loop:
var Editor = function() {
this.document = {}
this.change = () => { this.document = {} }
}
var data = new Vue({
data: () => ({
editor: new Editor(),
check: 0
}),
watch: {
editor: {
handler() {
this.check++
console.log('Changed')
if (this.check < 5)
this.editor.change()
else
console.log('Infinite loop!')
},
deep: true,
immediate: true
}
}
})
data.editor.change()
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
In such case, extra checking is necessary before making the change.
Is there a way to have a static variable in a dojo (1.8) module so that I can retain state?
Example, say I set some value in some/module
require([
'some/module'
], function (module) {
module.setSomeValue(3);
});
.. and then want to retrieve it later
define([
'some/module'
], function(module) {
return {
start: function() {
var x = module.getSomeValue();
}
};
});
A solution that works but seems like a hack,
acompany = window.acompany || {};
acompany.project = acompany.project || {
};
require([
], function() {
var debug = false;
acompany.project.module = {
/* static variables and functions here */
};
});
define([
], function () {
return acompany.project.module;
});
Actually there is always only single instance of AMD module, because (source):
define has two additional important characteristics that may not be immediately obvious:
Module creation is lazy and asynchronous, and does not occur immediately when define is called. This means that factory is not executed, and any dependencies of the module will not be resolved, until some running code actually requires the module.
Once a module value has been entered into the module namespace, it is not recomputed each time it is demanded. On a practical level, this means that factory is only invoked once, and the returned value is cached and shared among all code that uses a given module. (Note: the dojo loader includes the nonstandard function require.undef, which undefines a module value.)
In addition you do not have to provide just factory function, you can provide an object literal as well:
define("some/module", {
someValue: "some",
otherValue: "other"
});
Then somewhere else in your code:
require(["some/module"], function(module) {
console.log("module.someValue", module.someValue); // some
module.someValue = "some changed";
});
require(["some/module"], function(module) {
console.log("module.someValue", module.someValue); // some changed
});
More robust solution includes an instance of dojo/Stateful, so you can watch for changes and define custom setters and getters:
define("some/stateful-module", ["dojo/Stateful"], function(Stateful){
var stateful = new Stateful({
someValue: "some",
otherValue: "other"
});
return stateful;
});
Then somewhere else in your code:
require(["some/stateful-module"], function(module) {
console.log("stateful-module.someValue:", module.get("someValue"));
module.watch(function(name, oldValue, newValue) {
console.log("stateful-module: property"
, name
, "changed from"
, "'" + oldValue + "'"
, "to"
, "'" + newValue + "'"
);
});
});
require(["some/stateful-module"], function(module) {
module.set("someValue", "some changed");
});
See how it works at jsFiddle: http://jsfiddle.net/phusick/fHvZf/. It's in a single file there, but it will work the same way across the whole application unless you require.undef(mid) the module.
There are multiple files in Dojo like dojo/date/locale that define static variables and functions and not widgets/classes using dojo.declare.
Define the module
define([
'dojo/_base/lang/',
'some/module'
], function(lang, module) {
var m = lang.getObject('some.module', true);
m.x = 0;
m.doSomething = function(){
// doSomething
};
return m;
});
Use the module
require([
'some/module'
], function(someModule) {
var debug = false;
/* someModule - static variables and functions here */
if(someModule.x == 0){
}
});
1-I used following code to define a reusable grid,
but when I make instance, no config in class definition either do not have effect of break the code. What is the reason?
3- Is there any restriction in class config declaration?
2- How I can make some default columns in grid class and add some more columns to its objects?
Thanks
Ext.define("IBS.users.Grid", {
extend: "Ext.grid.Panel",
config:{
selType:'checkboxmodel', //not work
dockedItems:[/* items */], //break
multiSelect:true,
features: [
{
groupHeaderTpl: '{name}',
ftype: 'groupingsummary'
},
{
ftype:'filters',
encode: false, // json encode the filter query
local: true
}
],
viewConfig: { //not work
stripeRows: true,
filterable:true,
loadMask: false
},
listeners : {
itemdblclick: function(dv, record, item, index, e) {
console.log(arguments);
}
}
},
constructor:function(config) {
this.callParent(arguments);
this.initConfig(config);
// this.self.instanceCount++;
}
});
1-I used following code to define a reusable grid, but when I make instance, no config in class definition either do not have effect of break the code. What is the reason?
I can answer why your config doesn't have effect. Because config which is being passed into cunstructor is not your default config. You have to apply your default config in order to make default config to have effect:
constructor:function(config) {
config = Ext.applyIf(config, this.config);
this.callParent(arguments);
this.initConfig(config);
}
However, I don't know why dockedItems:[/* items */] breaks the code. Maybe you have syntax or logical errors somewhere within /* items */.
2- How I can make some default columns in grid class and add some more
columns to its objects?
That is easy. Just override your initComponent function:
Ext.define("IBS.users.Grid", {
extend: "Ext.grid.Panel",
// ...
initComponent : function(){
if (!this.columns) {
// default columns:
this.columns = [{
dataIndex: 'dkjgkjd',
// ...
}];
// if we passed extraColumns config
if (this.extraColumns)
for (var i=0; i < this.extraColumns.length; i++)
this.columns.push(this.extraColumns[i]);
}
this.callParent(arguments);
},
// ...
});
3- Is there any restriction in class config declaration?
I'm not aware of any. However, I wouldn't recommend to declare object configs in class definition. For example:
Ext.define("IBS.users.Grid", {
extend: "Ext.grid.Panel",
bbar: Ext.create('Ext.toolbar.Toolbar', // ...
// ...
});
It will be ok with first instance of the class. But when you create the second instance it's bbar refers to the same object as the first instance. And therefore bbar will disappear from the first grid.
Instead declare object configs in initComponent.
I am actually playing with Javascript doing a small game and I would like to implement what I've found on http://www.crockford.com/javascript/inheritance.html which is something similar to:
ZParenizor.method('toString', function () {
if (this.getValue()) {
return this.uber('toString');
}
return "-0-";
});
I can't find any reference the the library used to make such development possible. Any ideas? Otherwise, I'm looking for a good library that will aid my OOP developments.
Thank you
Edit:
I am looking for a OOP solution / library for Node.js. Please note that I'm new to Node.js
2 months later
Maybe you do need a library, ES5 is verbose as hell so I've created pd
Original answer
I am looking for a OOP solution / library for Node.js.
You don't need a library. You have ES5.
JavaScript does not have classical OOP. It has prototyping OOP.
This means you have only objects. The only thing you can do with objects is extend, manipulate and clone them.
Manipulate
var o = {};
o.foo = "bar";
Extend
var o = someObject;
Object.defineProperties(o, {
"foo": { value: "foo" },
"bar": { value: "bar" }
"method": { value: function () { } }
}
Clone
var o = someObject;
var p = Object.create(o);
Clone and extend
var o = someObject;
var p = Object.create(o, {
"foo": { value: "foo" },
"bar": { value: "bar" }
"method": { value: function () { } }
}
It's important to understand how Object.create, Object.defineProperty and Object.defineProperties work.
The cloning operation isn't actually cloning. It's creating a new object from a blueprint. A blueprint is an object. It places the blueprint in the [[Prototype]]. The [[Prototype]] lives in the .__proto__ property which I'll use for demonstration.
var o = {};
var p = Object.create(o);
p.__proto__ === o; // true
var q = Object.create(p);
q.__proto__.__proto__ === o;
var r = Object.create(q);
r.__proto__.__proto__.__proto__ === o;
Disclaimer: .__proto__ is deprecated. Don't use it in code. It has it's uses for debugging and sanity checks though.
The main point here is that accessing properties from o in r it has to walk 3 levels up the prototype chain and this gets expensive. To solve that problem, rather then cloning random objects you should clone specific blueprints (and you should have one blueprint per object).
// Parent blueprint
var Parent = (function _Parent() {
// create blank object
var self = Object.create({});
// object logic
return self;
}());
// factory function
var createParent = function _createParent(foo) {
// create a object with a Parent prototype
return Object.create(Parent, {
foo: { value: foo }
});
}
var Child = (function _Child() {
var self = Object.create(Parent);
// other stuff
return self;
}());
var createChild = function _createChild(bar) {
return Object.create(Child, {
bar: { value: bar }
})
};
Here's a snippet from some code I'm working on that you can use as an example:
var Sketchpad = (function _SketchPad() {
var self = Object.create({});
var mousemove = function _mousemove(e) {
this.drawLine(e);
};
self._init = function _init() {
this.$elem.bind({
"mousemove": mousemove.bind(this),
});
this.pens = {};
$("#clear").bind("click", this.clear.bind(this));
$("#undo").bind("click", (function _undoPath() {
this.pen.undo();
}).bind(this));
return this;
};
self.clear = function() {
this.paper.clear();
};
return self;
}());
createSketch = function _createSketchPad(id, w, h) {
var paper = Raphael(id, w, h);
var pen = createPen(paper);
var o = Object.create(Sketchpad, {
paper: { value: paper },
$elem: { value: $("#" + id) },
pen: {
get: function() { return pen; },
set: function(v) { pen = v; }
}
});
return o._init();
};
MooTools is one of the best libraries in terms of OOP Javascript.
You can create classes, interfaces, use inheritance, etc.
Documentation
http://mootools.net/docs/core
Tutorial - MooTools OOP
http://www.phpeveryday.com/articles/MooTools-Basic-Creating-Classes-MooTools-P919.html
You might also be interested in GNU ease.js. If you are not interested in the library itself, its manual goes extensively into the implementation details.
You could also see the author's paper on Classical OOP in ECMAScript.
You could try Joose, https://github.com/SamuraiJack/Task-Joose-NodeJS. Although, I'd personally recommend to stick with Javascript's object functionality as provided by ES5.
In the article you referenced, he was simply giving an example of what was possible with inheritance in javascript. He was not using a framework, but showing you how to extend your own classes you have written.
Frameworks for javascript include Backbone.js (mvc), and MooTools (oop).
extjs has support for OOP with Ext.define and Ext.extend (and Ext.ns). See this example on Sencha.com
Ext.extend is the older method, but is still sometimes useful. You would do something like this:
Ext.ns('myApp.myPackage'); // create a namespace
(function() { // this adds it to the namespace
var MyClass = Ext.extend(BaseClass, {
property: 1,
constructor: function(config) {
Ext.apply(this, config);
},
method: function(a, b) {
this.property = a + b;
}
});
myApp.myPackage.MyClass = MyClass;
}) ()
With Ext.define in Ext 4+ you can do:
Ext.define('myApp.myPackage.MyClass', // don't need to define the namespace first
extend: 'BaseClass' // notice the base class is referenced by a string,
requires: 'AnotherClass',
mixins: { mixin : 'MixinPackage' },
property: 1,
constructor: function(config) {
//...
}
method: function(a, b) {
this.property = a + b;
}
});
Note that you can also use traditional OOP in javascript with 'new' and function.prototype
If you want to do a real strong OOP in Javascript/Node, you can have a look at the full-stack open source framework Danf.
It allows you to use OOP (and so the same classes) on both the server (node) and client (browser) sides.
It also provides a nice dependency injection mechanism (looking as the one of Symfony2 if you come from the PHP community).