What is the purpose of using getters and setters in angular2? - javascript

i am new to angular2 and when i was reviewing someone's code, one specific line got me confused
get formData() { return <FormArray>this.lienHolder.get('policyDetails'); }
why is the above line any different from this
formData() { return <FormArray>this.lienHolder.get('policyDetails'); }
I searched about this in google and found no actual results, can anyone help me to understand this.
UPDATE
what is the difference between this
var obj = { log: 0, get latest() { return this.log++; } };
and this
var obj = { log: 0, latest() { return this.log++; } };
both are giving me the updated value all the time i call them
obj.latest & obj.latest() -- returns updated result all the time then why use one over another?

get formData()
is called a getter accessor. It allows you get the property dynamically. It always should return a value.
https://www.typescriptlang.org/docs/handbook/classes.html
TypeScript supports getters/setters as a way of intercepting accesses
to a member of an object. This gives you a way of having finer-grained
control over how a member is accessed on each object.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
Sometimes it is desirable to allow access to a property that returns a
dynamically computed value, or you may want to reflect the status of
an internal variable without requiring the use of explicit method
calls. In JavaScript, this can be accomplished with the use of a
getter.
In opposite to that, getFormDate() is a function, it can take arguments and not always returns values.
One of the cases, where I like to use a getter is when a property should be get from a service:
<p>{{dictionary.label1}}</p>
and then I get it from a service like this:
get dictionary(){
return this.myService.getDictionary();
}
this way when the service changed the data I dynamically can receive the value to my binding/model.
If I would have defined as the following:
dictionary: [];
ngOnInit(){
this.dictionary = this.myService.getDictionary();
}
then I would be 'stuck' with the old data while the service already received the new set of data. Of course, you can then set a change listener and trigger the update, but it's more code!
Think of getters as dynamic class properties.
UPDATE:
For the examples in your updated post, it's true, they give the same result, and it's a good thing! You can use both, but as they don't work similarly, you can have more options in some cases. It's not like only one or only the other, or which one is the best. In most of cases you can use both, it's where and for what you need to use them. Most of the times, it's a method which is used, as it has more comprehensive use: we use methods with or without parameters, to trigger actions on objects. But in some cases, again, it will not have the same flexibility as a getter. If you are hesitant which one to use, use the method first and when you see its limits, think if the getter would help you, as now you know what's its purpose, which is - a property, but dynamic!
An other example:
isShown:boolean; //is 'static', will return the same value unless you change it in some kind of a method
get isShown(){
return this.someCondition && this.someMethodResult() || this.anotherCondition
}
If someCondition and anotherCondition change and the result from someMethodResult had to come changed you don't have to request isShown value, it's done dynamically.
Opposite of that, you can have
setShown(){ //the method
this.isShow = !this.isShown;
}
Here setShown needs to be called so isShown could be updated.
Also, a getter can easily replace a method which only job is to return a class property value.
UPDATE2:
An other 'good' example for get. A case when a component needs to check if the user is logged to show/hide some buttons. Instead of subscribing to changes, you do:
HTML:
<button [hidden]="!isLogged">Log out</button>
Typescript:
get isLoggedIn(){
return this.authService.isLoggedIn();
}
And that's it! If the user is logged out the button will be disabled 'immediatly'. No nead for the heavy subscribe/unsubscribe...

with the get you can treat it like a var:
let something = formData;
otherwise you must invoke the function:
let something = formData();
You would use a get usually to format data as you retrieve it. for example:
let _number = '12';
get number(){
return parseInt(_number);
}

Related

pg-promise format default - not existing Property to null

I would like to be able to have the formatting.formatValue function convert undefined into null.
But there does not appear to be a way that I can set the default function from the initOptions given to pg-promise as pgFormatting is a boolean, format value wants it as an argument. But the library does not appear to pass it for normal queries.
vitaly-t wrote
But i'm not sure how much value it would add, since you do not have access to formatting options from query methods.
And that is true. But I kind of just want to set a default of null for all missing values being formatted into queries. Partial does not mater I don't use it?
Using coalesce to have "optional" values in some of the queries, to default not set variables anyway.
Example:
UPDATE sometable SET value = COALESCE(${value}, value)
How can I stop getting the "Property doesn't exist Error?
I think that I need a way to pass a value to this options for all calls to the format.
if ('default' in options) {
const d = options.default, value = typeof d === 'function' ? d.call(obj, v.name, obj) : d;
return formatValue(value, v.fm, obj);
}
Related issue that led to creation of options.default.
https://github.com/vitaly-t/pg-promise/issues/173
I can't over-ride the format value function as it is added as a non configurable read only property.
Do I just have to bite the bullet and put the variables in as null everywhere I want them to be optional...
I kind of just want to set a default of null for all missing values being formatted into queries...
Here's your formatting function for this, if you want to format queries manually:
function format(query, values) {
return pgp.as.format(query, values, {'default': null});
}
And for automatically generated queries within the helpers namespace, you would provide the value for property def, as per the Column API.
Other than that, the query methods make use of the format function on their own, so you cannot override that, neither you should, it is generally not needed, if you make the right use of the library's API, i.e. if you can give me a specific example of where you think you need it, then I can advise you of the better approach that avoids it.
One other approach - method helpers.concat can consume the formatting options, as it implements a specific case of joining queries.

Object.assign not working as expected

I have one object called bookings, and inside it I have several properties, and i want extend with Object.assign, like this:
let data = Object.assign(booking, {
hiw: event.hiw[booking.locale],
tip: event.tip[booking.locale],
start: moment(event.start).format('L')
});
But when I print the data, the result will be the same object from the source (booking), so hiw, tip and start will be ignored, but... if I try to do:
let data = Object.assign({}, {
hiw: event.hiw[booking.locale],
tip: event.tip[booking.locale],
start: moment(event.start).format('L')
});
This will work perfect.
My question is: what am I doing wrong here? Why can't I extend booking and I can extend the empty object?
That's definitely not a problem with async code, when i try to extend booking, he already exist with all properties inside.
I also was trying to use underscore extend method, and the behavior is exactly the same.
Mongoose documents (model instances) are special: they will only print properties that are present in the schema.
If properties aren't defined there, they won't show up when you console.log() them (and also not if you convert the document to a plain JS object with obj.toObject()).
This means that using Object.assign() will only work if you assign properties that are also present in the schema. Any properties that aren't declared will not be shown (nor saved to the database).
If your intention is to use the document for output, you should convert it to a proper JS object first before assigning to it:
let data = Object.assign(booking.toObject(), {
hiw : event.hiw[booking.locale],
tip : event.tip[booking.locale],
start : moment(event.start).format('L')
});

JavaScript subclassing in Parse.com

In Android I subclassed ParseObject with two local variables that are not in Parse class. I just needed to set those variables locally and had no need to save them on server. They are String's named helper1 and helper2 with getters and setters as well.
It works all fine on Android - I can use setHelper1("whatever"); as well as getHelper() methods on my ParseObject's.
What I want to do is to do the same in JavaScript since I want to make same operation in ParseCloud and make it return results with that additional Strings without creating additional columns in database class.
I read https://parse.com/docs/js/guide#objects-parse-object and https://parse.com/docs/js/guide#queries-basic-queries but it's not helping very much and I can't get it. How that could be achieved?
edit:
q1.find({
success: function(results){
for (var x in results){
x.helper1 = 'foo';
}
response.success(results);
},
error: function(error){
}
});
In JavaScrpt everything is easy. As far as I know, those parse-objects are stored in the form of a JSON object. (equivalently literal objects in JavaScript).
In JavaScript, If you'd like to add an additional property (playing role of a class member) to an existing object, it's enough to use this code.
var myobj = /* This is that parse-object */
// Add property helper1
myobj.helper1 = 'foo';
// Add property helper2
myobj.helper2 = 'bar';
For removing those properties, use this code.
// Remove property helper1
delete myobj.helper1;
// Remove property helper2
delete myobj.helper2;
Equivalently, you can use [] to create and access a property.
// Add property help1
myobj['helper1'] = 'foo';
// Access it
console.log(myobj['helper1']);
I resolved that, by using #Hi I'm frogatto's answers, but it appeared that You can do that on server-side or client-side, but only locally. So when I send data with setted helper1 or helper2 those just vanished so I had to do that operation on client-side which exposes a bit of business logic.
My question is still valid. Still, many of You should get helpful informations from frogatto's answers. Use my answer as a workaround.

Modify JavaScript object inside function, return to original if error

I've got a JavaScript object in JSON format that needs to be modified based of a set input (delete foo or add bar, etc). This input can have cascading effects (delete foo might require foobar to be deleted first, based on a set of rules). If half way through a cascade something breaks I don't want the JavaScript object with half the modifications, I want to go back to the original unmodified object.
I could obviously just send a copy of the object into the modification function then not replace the original if the function returns an error. The issue with this is that the JavaScript object is around 25 megabytes, so a copy of it would mean a significant increase in memory usage by the browser. So I would like to do this without creating a copy of the object. I can just have the initial object be an input to the function and modify it recursively, but then if there is an error after some calls it could return a modified object when I don't want it to.
Would there be a way to do what I am trying to do? Keep track of the changes and easily undo them after an error, or something? Thanks.
It is possible to create a transaction array that records each change made to the object and records enough data about the change such that it can be undone. This is not a trivial amount of work to do. It is somewhat similar to the undo capabilities in a word processor or spreadsheet for example. If you record the right level of information and keep it in order in an array, it should be possible to reverse all the changes. This is not rocket science, but it is a bit of code to write and test.
As mentioned in a comment, the larger question raised here is about a single 25MB object that has to be operated on by one function. I'd personally wonder if you can break up the data into smaller pieces and be able to use smaller copies of things in order to not have to write this whole undo operation.
Also, it's worth considering whether you can pre-flight enough of the operations to know ahead of time whether the code will fail before you've modified the object or not. For example, I've used code before that runs all the same logic as the code that modifies the object, but it doesn't actually modify the object. This allows you to run a pre-flight of the entire operation and thus find out if anything fails some check before you've actually modified the object. Written appropriately, you can use the same code for pre-flight as for actual modification with just an extra flag passed in. How feasible this is depends upon the exact nature of the modification operation, something you haven't disclosed.
Here's an example of such code that handles changes to a specific object property. This could be extended to include array manipulations too.
Working demo: http://jsfiddle.net/jfriend00/ohqL0p06/
Code:
function TransactionSummary() {
this.transactions = [];
}
TransactionSummary.prototype = {
deleteProperty: function(parent, property) {
this.rememberTransaction(parent, property, "delete", parent[property]);
delete parent[property];
},
modifyProperty: function(parent, property, newVal) {
this.rememberTransaction(parent, property, "modify", parent[property]);
parent[property] = newVal;
},
addProperty: function(parent, property, newVal) {
this.rememberTransaction(parent, property, "add");
parent[property] = newVal;
},
rememberTransaction: function(parent, property, type, oldVal) {
this.transactions.push({parent: parent, property: property, type: type, oldVal: oldVal});
},
undoTransactions: function() {
var t;
while (this.transactions.length) {
t = this.transactions.pop();
switch(t.type) {
case "delete":
case "modify":
t.parent[t.property] = t.oldVal;
break;
case "add":
delete parent[property];
break;
}
}
}
}

Struggling for Backbone syntax in collection events

I have a collection, I can do this successfully ('this' is the collection instance):
this.on('change:username', function(model,property,something){
// model is backbone model that changed
// property is the property that changed (username in this case)
// something is some empty mystery object that I can't identify
}
however what I want to do is this:
this.on('change', function(model,property,something){
// model is backbone model that changed
// ***how can I read the properties that changed here?***
// something is some empty mystery object that I can't identify
}
the problem is that in the second case, I can't get the property that changed...maybe that's because it's potentially multiple property changes all at once.
How can I capture that properties that changed in the second case? is this possible?
The only way I know how to do this would be
this.on('change', function(model, something){
// something object is unidentifiable
var changed = model.changed; //hash of changed attributes
}
so my other question is: what is that mystery object "something"? It is just an empty object...?
You have a couple of options you can use in general change events:
Backbone.Model#hasChanged: This will allow you to see if a model attribute has changed in the context of this change event. If so, you can get its new value and apply it to the view (or whatever other context) as needed.
Backbone.Model#changedAttributes: This will allow you to get all changed attributes since the last set() call. When called with no parameters, it is a defensively cloned copy of the changed hash; you can also pass in a hash of parameters and get only what is different about the model relative to that set of key/value pairs.
Backbone.Model#previous: This will allow you to get the previous value of a model attribute during a change event.
Backbone.Model#previousAttributes: This will allow you to get all the previous values of a model during a change event. You could use this to completely undo a change (by calling set with the result of this function) if you wanted to.
By the way, the third parameter of the change:attr event (and the second of change) is an options object, which can be useful if you want to specify custom values that can be read by your event handlers. There are also a number of standard options Backbone will handle specially. See the documentation for Backbone.Model#set for more information on the specific options, and take a look at the Backbone event list to see the callback signatures expected when those events are triggered.

Categories

Resources