Suppose there is a Qml type called Test with foo property, it is implemented as follows:
Test.qml
// Not necessarily QtObject, but derived from QObject
QtObject {
// Not necessarily var/property, but must behave like property (i.e. be accessible using "<instance>.foo")
property var foo
}
And used in the following way:
main.qml
import "."
Test {
id: _test
}
function baz() {
var x = _test.foo;
_test.foo = x;
}
What I want is to be notified every time foo property is accessed by getter or setter. For setter perhaps I can use fooChanged signal, but there is no such solution for getter. Also I could implement Test type as a C++ class with Q_PROPERTY macro and emit corresponding signals form property getter/setter, but I would really like to leave most of the code on Qml side.
Is there any other way to hook Qml properties access?
Ok, after some hours of googling, reading Qml and JS documentation I think I have finally found a solution. It involves some hacks since JS is not fully supported in Qml, but this solution still works. The main idea is to use JS defineProperty method in order to add properties to existing objects dynamically. Now my Test.qml file looks like this:
QtObject {
// NOTE: .defineProperty does not correctly work for Qml objects, so JS object is used instead
property var object: { return {}; }
Component.onCompleted: {
Object.defineProperty(
object,
"foo",
{
get: function () {
// getter handling here
},
set: function (value) {
// setter handling here
}
}
);
}
}
And in main.qml _test instance is declared as follows:
property alias _test: _testDeclaration.object
Test {
id: _testDeclaration
}
Hope this answer will help other people.
Related
How does Angular resolve all it's variables regardless of where there placed in a component?
For example in Vanilla JS
console.log(a) // undefined
let a = 'Hello;
Angular component
ngOnInit(){
this.example()
}
example(){
console.log(this.a) // Hello
}
a = 'Hello'
I'm aware that this is bad practice and the compiler will complain about that placement of the variable but none the less I am curious how Angular achieves this, or whether it's not an Angular specific behaviour?
This is not an Angular behavior. Actually the piece of code that you provided is inside a class, and the a is not a variable, actually it's a property.
JavaScript (and Typescript) doesn't requires properties to be declared before methods (neither constructor), since it's just a declaration that will be used futurely when this class will be instantiated.
Although tslint may warn you about the placement of it after methods, it's just a coding style concern.
You may translate a class to a traditional function constructor:
class Car {
make = 'default';
drive() {
/* ... */
}
model = 'foo'
}
can be wrote as (and is converted to when using some polyfill on browsers that doesn't support ES6 Class):
var Car = function() {
this.make = 'default';
this.model = 'foo';
}
Car.prototype.drive = function() {
/* ... */
}
Note that in the second case, the properties are defined inside the constructor, so it will always run before the method be called.
I'm implementing a client-side application using ECMAScript6 and use JSHint for static code analysis. I often use the following pattern in my code:
class MyClass {
constructor() {
//This is how I would like to call myMethod
myMethod();
//This is how I should call myMethod to make JSHint analysis pass
this.myMethod();
}
myMethod(){
//Implementation
}
}
My primary language is Java so I expect that simply calling myMethod() should be ok. However without adding this to method call I'm getting "'myMethod' is not defined" warning from JSHint. My questions are:
Is it correct to make calls without this in such situation? (e.g. in PHP you always need to add $this-> to non-static method call)
If that's correct to make calls without this is there any way (any .jshintrc flag) to turn off this warning in JSHint?
No, this is and never was correct in JavaScript. Methods always need to be called on a receiver explicitly to make this work, and they need to be referred to using property access notation because methods are just functions on properties in javascript. They're not available as functions in the scope of your other methods. It's the same for properties, btw.
JsHint is right here, and there's no reason to turn that warning off. Even if that may possible, executing your program in spite of that would just make it not work.
Is it correct to make calls without this in such situation? (e.g. in
PHP you always need to add $this-> to non-static method call)
No, it is not. You always have to specify the receiver of the method.
If that's correct to make calls without this is there any way (any
.jshintrc flag) to turn off this warning in JSHint?
JSHint returns "'myMethod' is not defined" warning correctly as there is not function called myMethod in the scope of the constructor.
In the code you provided the identifier myMethod isn't defined, but the inherited property myMethod of instances of MyClass is defined.
If you define myMethod as a Function under a closure which isn't available elsewhere then you can access as it in the form you desire
var MyClass = (function () {
function myMethod() {
//Implementation
}
class MyClass {
constructor() {
myMethod();
}
}
return MyClass;
}());
I don't get to write much ES6 so I'm not sure if putting the function myMethod inside MyClass's definition is a SyntaxError
Please note however that this is required to reference your specific instance of MyClass, so you'll probably need to use it somewhere if you want MyMethod to act on the instance.
function myMethod(obj) {...}
// ...
myMethod(this);
If you read the MDN's description of class
JavaScript classes are introduced in ECMAScript 6 and are syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax is not introducing a new object-oriented inheritance model to JavaScript. JS classes provide a much simpler and clearer syntax to create objects and dealing with inheritance.
This is saying using class is just shorthand for the old way of doing it, not a new model, so it may be easier to think of what your current code would look like if written in ES5,
var MyClass = (function () {
function MyClass() {
this.constructor.apply(this, arguments);
}
MyClass.prototype = Object.create(null);
MyClass.prototype.constructor = function () {
myMethod(); // referenceError
this.myMethod(); // works
};
MyClass.prototype.myMethod = function () {
//Implementation
};
return MyClass;
}());
I have been using JS Modular pattern throughout the application. The modules look like the following:
var moduleName = {
prop1 : 'value1',
prop2 : 'value2',
fun1Name : function () {
// body of funName
moduleName.fun2Name(); // notice the way I am calling the function using moduleName
// Didn't use this.fun2Name()
},
fun2Name : function () {
// body of functName
}
};
And inside the modules, I have been accessing the functions using moduleName.functionName() which may also be accessed (as we all know) using this.functionName(). Now I am refactoring the code and I was just curious to know that:
Is there any reason that I should change moduleName.functionName() to this.functionName() wherever possible?
Are there any performance issues associated with both the ways of calling the module functions?
What's the best way to call the module functions inside the module itself?
It makes your code reusable between different but similar objects (typically instances of the same constructor function)
No
That's subjective
Basically Dub and Dub.socialize objects already exist as an included library. I'm trying to extend the library with some additional custom functions that I created.
I attempted the following concept below:
Dub.socialize = {
setUID : function(preUID, postUID)
{
// .. function code here
}
}
However, I receive the following error "Uncaught TypeError: Cannot set property 'setUID' of undefined" from my console.
Obviously my knowledge of objects is a bit misled. What would be the proper method of extending this function into the already existing object library?
A simple solution could be
Dub.socialize.setUID = function(preUID, postUID) {};
Try this:
Dub.socialize.prototype.setUID = function(preUID, postUID) {
...
};
Object Constructor and prototyping
Edit: Realized you're working with a "static" object. This only works for something that is instantiated, and since you're not making new instances, this doesn't apply.
If you are going to create the function for declared object means then you have to use "prototype" keyword for example.
`var Dub = {
socialize: new Object()
};
Dub.socialize.prototype.setUID = function(preUID, postUID) {
// Function Body
};`
http://www.javascriptkit.com/javatutors/proto3.shtml
I have been reading through the dojo 1.9 documentation about declare.safeMixin(), focusing on the difference between it and lang.mixin.
Here is the explanation I found...
safeMixin() is a function defined in dojo/declare. It has the same functionality as dojo/_base/lang::mixin(), but additionally it annotates all copied methods compatibly with dojo/declare. This decoration can affect how this.inherited() works in mixed-in methods.
I can follow the example but it doesn't really explain exactly what is added and where, can anyone give any further examples of what annotation is added to each copied method?
So to be clear, I'm not asking for an explanation of inheritance, I'm just asking specifically about the annotations added by using declare.safeMixin() instead of lang.mixin.
Using safeMixin allows you to mix functions into an instance that can take advantage of this.inherited the same way that prototype methods defined using declare can.
For example, the following will log 2 messages:
require([
"dojo/_base/lang",
"dojo/_base/declare"
], function(lang, declare){
var A = declare(null, {
method: function () {
console.log('method in prototype');
}
});
var a = new A();
declare.safeMixin(a, {
method: function () {
this.inherited(arguments);
console.log('method in instance');
}
});
a.method();
});
Without safeMixin, you wouldn't be able to call this.inherited(arguments) from the overriding method (at least, not without additional parameters) - you'd end up getting an error:
Error: declare: can't deduce a name to call inherited()
safeMixin adds the nom property to functions that are mixed in to the target. This property is set to the key from the source object that the function was assigned to. e.g. if you call declare.safeMixin(target, { foo: function() {} }), the nom property for that function is "foo". This is necessary for this.inherited(arguments) to automatically figure out that it should call the parent "foo". The alternative to using safeMixin would be to explicitly specify the name of the parent function: this.inherited('foo', arguments);.