How can I create config members with a getter or setter only but not both at the same time?
By default it creates both a getter and setter.
Ext.define('Myapp.myclass', {
config: {
conf1 : true, // Make this only have setter.
conf2 : false // Make this only have getter.
},
constructor: function(config) {
this.apply(config);
}
});
Configs actually create 4 helper methods, which are quite useful.
_config1 this is where the value gets saved
getConfig1 gets you the value
applyConfig1 allows you to check if the setter value is valid
updateConfig1 do some stuff to dom elements
setConfig1 call applyConfig1 and updateConfig1 if available and set the value to _config1. Usually you dont want to touch this, but use updateConfig1
If you do not want these then you have to do the work yourself, but you might not get bindables or other ExtJS out of the box functionality. For me it does not make a lot of sense not to use configs.
Ext.define('Myapp.myclass', {
_conf1: true, // Make this only have setter.
setConfig1: function(value) {
let oldValue = this._config1;
if(oldValue === value) return;
this._config1 = value;
},
_conf2: true, // Make this only have getter.
getConfig2: function() {
return this._config2;
}
});
Related
I have a Vue block that I need to bind to a boolean property:
<div class="row" v-if.sync="isThisAllowed">
To calculate that property I need to make an API call using Axios, which has to be asynchronous. I've written the necessary code to get the value:
public async checkAllowed(): Promise<boolean> {
var allowed = false;
await Axios.get(`/api/isItAllowed`).then((result) => {
var myObjects = <MyObject[]>result.data.results;
myObjects.forEach(function (object) {
if (object.isAllowed == true) {
hasValuedGia = true;
}
})
});
return allowed;
}
What I did then - I'm not very experienced with Vue - is to add a property to the Vue model and assign a value to it in created:
public isThisAllowed: boolean = false;
async created() {
this.checkAllowed().then(result => {
this.isThisAllowed = result;
});
}
This works in the sense that the value I'm expecting is assigned to the property. But Vue doesn't like it and complains
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value.
Most of the values on the model are exposed via getters:
get isSomethingElseAllowed(): boolean {
return this.productCode === ProductTypes.AcmeWidgets;
}
But I need to "await" the value of the async function, which would mean making the getter async which then, of course, makes it a Promise and I can't bind that to my model?
What's the right way to go about this?
You can't define a property that way, instead define isThisAllowed in the data object
as
data: function(){
return {
isThisAllowed: false
}
}
And make checkAllowed into a normal function and set this.isThisAllowed = allowed inside it
I'm creating a re-usable object that would contain multiple properties. I would like to fire an event within the object that will update some of its own properties when a specific property is changed through assignment. I have read something similar to this but what they used was an object. How can I achieve this?
My apologies if this is something basic but I don't really have a formal training is JavaScript or in-dept knowledge how JavaScript works.
also I would like to add that this is something that should work in IE11 and up.
I have tested the method from this but unfortunately I don't really understand how can I implement it on my case.
Listening for variable changes in JavaScript
var test;
function myObject(){
this.dataSource = null;
this.changeEvent = function(val){
//do something inside
}
}
test = new myObject();
test.dataSource = 'dataSource'; //trigger changeEvent() inside myObject
When creating the object, wrap it in a Proxy.
The Proxy object is used to define custom behavior for fundamental operations (e.g. property lookup, assignment, enumeration, function invocation, etc).
Implement a set trap which performs the needed internal changes.
OK, so I'll start from the method you've suggested and it seems you like that approach.
Sorry, if this seems obvious but better to explain!
Basically watch watches properties within your object (say datasource) and when a new value is assigned - fires the callback function. So, watch takes two params - what to watch, and what to do (when the property you are watching changes).
The caveat with this approach is it's a a non-standard and was not implemented by other browsers. Although, we can get a polyfill (which declares it if it does not exist).
https://gist.github.com/eligrey/384583
Warning from Mozilla's own docs:
Deprecation warning: Do not use watch() and unwatch()! These two
methods were implemented only in Firefox prior to version 58, they're
deprecated and removed in Firefox 58+. In addition, using watchpoints
has a serious negative impact on performance, which is especially true
when used on global objects, such as window. You can usually use
setters and getters or proxies instead.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/watch
So, to implement using a polyfil of watch (thank Eli Grey for the Polyfill)
First, register the polyfill (put it somewhere which will run before anything else in JS, or put it in a polyfill.js file and import it first on your HTML page!)
/*
* object.watch polyfill
*
* 2012-04-03
*
* By Eli Grey, http://eligrey.com
* Public Domain.
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*/
// object.watch
if (!Object.prototype.watch) {
Object.defineProperty(Object.prototype, "watch", {
enumerable: false
, configurable: true
, writable: false
, value: function (prop, handler) {
var
oldval = this[prop]
, newval = oldval
, getter = function () {
return newval;
}
, setter = function (val) {
oldval = newval;
return newval = handler.call(this, prop, oldval, val);
}
;
if (delete this[prop]) { // can't watch constants
Object.defineProperty(this, prop, {
get: getter
, set: setter
, enumerable: true
, configurable: true
});
}
}
});
}
// object.unwatch
if (!Object.prototype.unwatch) {
Object.defineProperty(Object.prototype, "unwatch", {
enumerable: false
, configurable: true
, writable: false
, value: function (prop) {
var val = this[prop];
delete this[prop]; // remove accessors
this[prop] = val;
}
});
}
Then, to use (using your example);
var test;
**function myObject(){
this.dataSource = null;
this.changeEvent = function (id, oldval, newval) {
console.log(id + ' changed from ' + oldval + ' to ' + newval);
return newval;
}
this.watch('datasource', this.changeEvent);
}**
test = new myObject();
test.dataSource = 'dataSource'; //trigger changeEvent() inside myObject
However, I would look into Event Listeners and trigger events when objects change - but that solution should work for you, especially with watch
Listening for variable changes in JavaScript
You can store the value of dataSource in local storage and then compare and check if it has been changed.
var test;
function myObject()
{
this.dataSource = null;
this.changeEvent = function(val)
{
console.log("Value has been changed.");
}
}
test = new myObject();
test.dataSource = 'dataSource';
console.log("Before change" + test.dataSource);
localStorage.setItem("dataSource", test.dataSource);
var newVal = "dtSrc";
test.dataSource = newVal;
var originalVal = localStorage.getItem("dataSource");
console.log("After change" + test.dataSource);
if(newVal == originalVal)
console.log("Value has not changed.");
else
test.changeEvent();
Let me know if it works for you. If not, let me know the expected output.
You can use like :
var myObject = {
_dataSource: null,
changeEvent : function(val){
//do something inside
alert(val);
}
};
Object.defineProperty(myObject, "dataSource", {
get: function(){
return this._dataSource;
},
set: function(newValue){
this._dataSource=newValue;
this.changeEvent(this.dataSource);
}
});
myObject.dataSource= "dataSource";
Say, I have an object type that implements a 3D-object, which has both quaternion and 3-axis rotation properties:
Object.defineProperty(MyObject3D.prototype, 'rotation', {
...
});
Object.defineProperty(MyObject3D.prototype, 'quaternion', {
...
});
and I want to make sure that each time I modify each of them, another property is recalculated automatically. Obviously, if I make both set methods of those properties, I'll run into infinite loop.
So far, the only way of doing this that I can see is to actually use another set of properties that resemble rotation and quaternion (probably non-enumerable, for a bit cleaner object introspection):
Object.defineProperty(MyObject3D.prototype, '_rotation', {
enumerable: false
});
Object.defineProperty(MyObject3D.prototype, '_quaternion', {
enumerable: false
});
Object.defineProperty(MyObject3D.prototype, 'rotation', {
get: function() {
return this._rotation;
},
set: function(r) {
this._rotation = r;
this._quaternion = rotation2quaternion(r);
}
});
Object.defineProperty(MyObject3D.prototype, 'quaternion', {
get: function() {
return this._rotation;
},
set: function(q) {
this._quaternion = q;
this._rotation= quaternion2rotation(q);
}
});
Any better ways you can come up with? Maybe I'm missing some abilities of Object.defineProperty that could make this even cleaner and shorter?
Instead of making rotation and quaternion accessor properties wouldn't it be simpler to make them data properties and then define a setRotation and a setQuaternion method to mutate them? For example:
function MyObject3D() {
...
}
MyObject3D.prototype.setRotation = function (r) {
this.quaternion = rotation2quaternion(r);
this.rotation = r
return this;
};
MyObject3D.prototype.setQuaternion = function (q) {
this.rotation = quaternion2rotation(q);
this.quaternion = q;
return this;
};
Now you can access .rotation and .quaternion normally. However to set them you use .setRotation and .setQuaternion instead. Yes it is unsafe since the user may manually set .rotation and .quaternion. However it has several advantages:
It will work in browsers which don't support defineProperty.
It allows you to chain operations since it returns this.
It's easy to understand what the functions do.
Another way to solve this problem would be to use immutable objects. This is the way you would do it in Haskell. For example:
function MyObject3D(rotation, quaternion) {
this.quaternion = quaternion;
this.rotation = rotation;
Object.freeze(this);
}
MyObject3D.prototype.putRotation = function (r) {
return new MyObject3D(r, rotation2quaternion(r));
};
MyObject3D.prototype.putQuaternion = function (q) {
return new MyObject3D(quaternion2rotation(q), q);
};
If you have some initialization logic in your constructor then you can move it into a smart constructor:
function createMyObject3D(r, q) {
// some initialization logic
return new MyObject3D(r, q);
}
Hence when you want to create a new object you use createMyObject3D and when you want to mutate the object you use new MyObject3D passing in the new values. The advantage of the following method is:
Your code becomes referentially transparent. Thus it can be subjected to equational reasoning.
It still allows you to chain operations since it returns a brand new object.
Nobody can tamper with the properties of your object.
It's easy to understand what the functions do.
The only disadvantage is that it depends upon Object.freeze which may not be present in old browsers. Nevertheless freezing the object is an optional step and can be omitted.
I want to be able to provide a JavaScript function that will be called whenever any property of a specified object is being queried or updated. Is that possible, if so, how?
To give a simple example, if I have obj = { a:3 }, I want to have some function called whenever any code queries obj.a, and be able to return whatever I want instead of its current value, e.g. 4 instead of 3.
It's easy, you can use Object.prototype.defineProperty. more on it here.
To answer your question:
var obj = {};
Object.defineProperty(obj, "a", {
get: function() {console.log("I've been accessed"); return 5;//or whatever value}
});
console.log(obj.a)
Working fiddle
Update
The above can be shorthanded.
Object.prototype.addMonitoredGetter = function(property, value, callback) {
Object.defineProperty(this, property, {
writable: false,
get: function() {callback(); return this[property]
};
};
And the callback here could be the monitoring function. Of course, needs default params and checks, but it should do the trick.
There's a watch method available for Firefox...
o.watch("p", function(...)
http://jsfiddle.net/NTc52/
I've been looking into JavaScript frameworks such as Angular and Meteor lately, and I was wondering how they know when an object property has changed so that they could update the DOM.
I was a bit surprised that Angular used plain old JS objects rather than requiring you to call some kind of getter/setter so that it could hook in and do the necessary updates. My understanding is that they just poll the objects regularly for changes.
But with the advent of getters and setters in JS 1.8.5, we can do better than that, can't we?
As a little proof-of-concept, I put together this script:
(Edit: updated code to add dependent-property/method support)
function dependentProperty(callback, deps) {
callback.__dependencies__ = deps;
return callback;
}
var person = {
firstName: 'Ryan',
lastName: 'Gosling',
fullName: dependentProperty(function() {
return person.firstName + ' ' + person.lastName;
}, ['firstName','lastName'])
};
function observable(obj) {
if (!obj.__properties__) Object.defineProperty(obj, '__properties__', {
__proto__: null,
configurable: false,
enumerable: false,
value: {},
writable: false
});
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
if(!obj.__properties__[prop]) obj.__properties__[prop] = {
value: null,
dependents: {},
listeners: []
};
if(obj[prop].__dependencies__) {
for(var i=0; i<obj[prop].__dependencies__.length; ++i) {
obj.__properties__[obj[prop].__dependencies__[i]].dependents[prop] = true;
}
delete obj[prop].__dependencies__;
}
obj.__properties__[prop].value = obj[prop];
delete obj[prop];
(function (prop) {
Object.defineProperty(obj, prop, {
get: function () {
return obj.__properties__[prop].value;
},
set: function (newValue) {
var oldValue = obj.__properties__[prop].value;
if(oldValue !== newValue) {
var oldDepValues = {};
for(var dep in obj.__properties__[prop].dependents) {
if(obj.__properties__[prop].dependents.hasOwnProperty(dep)) {
oldDepValues[dep] = obj.__properties__[dep].value();
}
}
obj.__properties__[prop].value = newValue;
for(var i=0; i<obj.__properties__[prop].listeners.length; ++i) {
obj.__properties__[prop].listeners[i](oldValue, newValue);
}
for(dep in obj.__properties__[prop].dependents) {
if(obj.__properties__[prop].dependents.hasOwnProperty(dep)) {
var newDepValue = obj.__properties__[dep].value();
for(i=0; i<obj.__properties__[dep].listeners.length; ++i) {
obj.__properties__[dep].listeners[i](oldDepValues[dep], newDepValue);
}
}
}
}
}
});
})(prop);
}
}
return obj;
}
function listen(obj, prop, callback) {
if(!obj.__properties__) throw 'object is not observable';
obj.__properties__[prop].listeners.push(callback);
}
observable(person);
listen(person, 'fullName', function(oldValue, newValue) {
console.log('Name changed from "'+oldValue+'" to "'+newValue+'"');
});
person.lastName = 'Reynolds';
Which logs:
Name changed from "Ryan Gosling" to "Ryan Reynolds"
The only problem I see is with defining methods such as fullName() on the person object which would depend on the other two properties. This requires a little extra markup on the object to allow developers to specify the dependency.
Other than that, are there any downsides to this approach?
JsFiddle
advent of getters and setters in JS 1.8.5 - are there any downsides to this approach?
You don't capture any property changes apart from the observed ones. Sure, this is enough for modeled entity objects, and for anything else we could use Proxies.
It's limited to browsers that support getters/setters, and maybe even proxies. But hey, who does care about outdated browsers? :-) And in restricted environments (Node.js) this doesn't hold at all.
Accessor properties (with getter and setter) are much slower than real get/set methods. Of course I don't expect them to be used in critical sections, and they can make code looking much fancier. Yet you need to keep that in the back of your mind. Also, the fancy-looking code can lead to misconceptions - normally you would expect property assignment/accessing to be a short (O(1)) operation, while with getters/setters there might be a lot of more happening. You will need to care not forgetting that, and the use of actual methods could help.
So if we know what we are doing, yes, we can do better.
Still, there is one huge point we need to remember: the synchronity/asynchronity (also have a look at this excellent answer). Angular's dirty checking allows you to change a bunch of properties at once, before the event fires in the next event loop turn. This helps to avoid (the propagation of) semantically invalid states.
Yet I see the synchronous getters/setters as a chance as well. They do allow us to declare the dependencies between properties and define the valid states by this. It will automatically ensure the correctness of the model, while we only have to change one property at a time (instead of changing firstName and fullName all the time, firstName is enough). Nevertheless, during dependency resolving that might not hold true so we need to care about it.
So, the listeners that are not related to the dependencies management should be fired asynchronous. Just setImmediate their loop.