Struggling for Backbone syntax in collection events - javascript

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.

Related

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

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);
}

How to delete an attribute when sending a partial object update to Algolia?

I need to use partialUpdateObject from the Algolia Javascript SDK to delete an attribute from an object that is already in the index.
My scenario is that I have a description field on my object that is optional. If the user originally sets a description and then later deletes it, I want to remove the description altogether from the object.
I do not want to overwrite the whole object (without the description attribute) because I have some count attributes on the object that I do not want to have to recalculate.
As far as I can tell in the documentation there isn't a way to do it and my workaround is to set the description as an empty string. Is that the recommended approach?
You're right: you cannot totally remove the attribute from an object with a partialUpdateObject operation. As a work-around you can set it to null, maybe that's enough for your use-case?
If you really want to delete the field you can :
Get your object with the search function
Store all fields values
Update (not partial update) your object without passing the field you want to delete

using `angular.copy ` to set model - what's the benefit?

Today I was reviewing this widget and found the following way to set property:
if (selected !== $scope.dropdownModel) {
angular.copy(selected, $scope.dropdownModel);
}
I'm wondering what's the benefit of such method as opposed to:
$scope.dropdownModel = selected;
Sometime you want to have a copy of the original model lying around so that you can reset the element's model to the original value, for example, if you have a form and the user edits it, then decides to cancel the changes, how would you revert the forms input value to the original ones? You need a copy of the original model since the binding between the model and the form is 2 way, and all changes made to the form will affect the model, so you need a copy of the original model if you want to roll back the edit. Angular.copy basically removes the reference from the object and creates a separate copy.

Should I use methods or subclasses? If that makes sense

A Little Background...
I have an an object called SineMacula which houses many methods for creating form elements and making these form elements do things on a page.
Firstly, when the page loads, a method called setFields() is called which loops through all the fields on a page and sets them appropriately i.e. autocomplete, checkbox etc...
The code for setFields() looks like this:
/**
* Set Fields
* This function will set all fields
*
* The options:
* - fields: the fields selector to loop through
*
* #param object options The field options
*/
SineMacula.prototype.setFields = function (options){
// Set the defaults for the fields
var options = $.extend({
fields: '.field', // Define the default field selector
},options);
// Loop through the fields and set the events
$(options.fields).each(function(){
// Set the field events
SineMacula.setBlur($(this));
SineMacula.setFocus($(this));
SineMacula.setToggleLabel($(this));
// If the field is a checkbox then set it
if($(this).parent().hasClass('checkbox')){
SineMacula.setCheckbox($(this).parent());
}
// If the field is an autocomplete then set it
if($(this).parent().hasClass('autocomplete')){
SineMacula.setDropdown($(this).parent(),{source:$(this).attr('data-source')});
}
// etc...
});
};
Most of the code above can be ignored, but I have inserted all of it so that you can see exactly what I am doing.
My Question
I have quite a few methods of the SineMacula object such as setCheckbox(), setDropdown()...
What I would like to know is, should I be treating these methods as objects in themselves?
So should my code look like this instead:
if($(this).parent().hasClass('autocomplete')){
new SineMacula.dropdown($(this).parent(),{source:$(this).attr('data-source')});
}
Notice the new keyword before calling the dropdown() method.
Is this a better method of working things? Will be use less memory etc?
There is no reason to create an instance of an object only to call the constructor and then throw the object away. By doing the work in the constructor you are just using it as a regular function, but with the overhead of creating an unused object.
(In fact you don't seem to use the SineMacula instance for anything either, other than as a namespace for the methods.)
As a general rule of thumb a new object appears when you need to delegate some responsibility to it. So if you later do something like sineMaculaInstance.setCheckboxValue(checkbox, true) it definitely looks like that should be checkbox responsibility.
Another way of looking at it is to analize the SineMacula object by the Single Responsibility Principle. In short, if you can describe what your object does in one or two lines you are generally ok. If you have to write an entire paragraph to state what SineMacula does, then it looks like you should refactor that object an split concrete responsibilities to other objects.
HTH
It seems to me, that since you are housing all of your methods within this SineMacula namespace / module, there is no purpose in re-instantiating another whole new SineMacula object.
Unless you were going to be adding different / specific prototypes/methods that you don't want attached to the original object, and are specific to a certain section or form element on your page.
var newThing = new SineMacula('doDifferentStuff');
newThing.dropdown = '''do something different''';
The whole reason for instantiating the class would also be to set the new this to be whatever you are invoking it from. And it seems like everything you have is already tied in together, and simply uses the SineMacula.setBlahblah of calling itself.
Hope that doesn't sound too garbled!

valueBinding to content of array

I have this controller with a value.
App.xcontroller = SC.ArrayController.create({
...some code...
array_values = [],
..more code...
})
Now i have somewhere in a view this valueBinding
valueBinding: 'App.xController.array_values',
When I change values in the array the view does not get updated. but when i do
the following in the controller:
var array_values = this.get('array_values');
... adding / removing values to the array....
if (x_values.contains(x)){
x_values.removeObject(x)
} else {
x_values.pushObject(x);
};
this.set('array_values', array_values.copy());
the binding works, the view gets updated. But ONLY with the copy().
I don't want to make a copy of the array, IMHO this is not efficient. I just want to
let the valueBinding know content has changed..
the x values are just a bunch of integers.
The reason i want this: I want to change the value key of a SegmentedItemView. I want to change the active buttons. But I do not know on forehand how many segmentedviews I have
so I thought i bind the value of every generated segemented view to some common array and change that common array to be able to change the active buttons on all of the segmented views. Since each button represents an item with an unique key it works fine. except that i have to copy the array each time.
set the content property of the xcontroller
Bind to the arrangedObjects property of the xcontroller
You need to use KVO compliant methods on the array to get the bindings to fire. The ArrayController itself has an addObject and removeObject methods. Arrays in SC have been augmented with a pushObject method (among others), which is also KVO compliant. So if you use the KVO methods the view should update.
The reason your view does not update is because you are bound to the array, but the array itself did not change. When you do a copy, the array itself changes, so the bindings fire.
You might also want to try
this.notifyPropertyChange('x_values');
in the controller after you make the changes, but that is less preferable to using the built in KVO functionality.

Categories

Resources