$watch collection change before item gets inserted to collection - javascript

I use ui-select multiple, and I need to check the collection, before ng-model="collection" gets updated, to see if new value is already in it.
$watching collection doesn't help, because the item is already added and then $watch gets called..
on-select neither helped me, same case, collection gets updated before, and I can't check if currently clicked item is already in it before it gets pushed.
Anyway i could test it, before ng-model gets updated?
The purpose of that, is to check for duplicates and to not add them.

If I understand the question correctly you can do this:
$scope.$watch('myArray', removeDuplicates);
removeDuplicates($scope.myArray)
function removeDuplicates(array){
...
};

Related

Angular JS digest cycle invoked multiple times

I am trying to understand the Angular1 $digest cycle. I've read in multiple articles that the digest cycle is called multiple times on every change.
In this article it says:
So once we traversed all of the $watch functions in the $watch list, are we done with the $digest loop? No, we go through the list ONE more time and verify that nothing has changed. We do this because there could have been a change to one of the values when another $watch item updated it. We continue through this loop until no changes are present in any of the values.
So my question is - in what scenario there could have been a change to one of the values when another $watch item updated it?
this may not be the perfect example in real use cases, but things like this could happen.
$scope.$watch('Var_A', function(){
// change Var_B
});
$scope.$watch('Var_B', function(){
// do something
});
Var_A and Var_B are put into the $watch list.
Say that there is an angular change that changes Var_A, it triggers the first $digest cycle and Var_B changes. The first $digest cycle is not aware Var_B has changed. It then goes through the list one more time and will find that Var_B changes. After this, it goes through the list again and makes sure nothing in the $watch list got changed.

Angular -> ng-repeat filtered array variable

Below I will put link to my example in Plunker to show you my problem.
In ng-repeat I have used array(filtrowane) to store data from filter result, also I have added ng-change on input for showing the value of filtrowane.length in console. Variable filtrowane is defined in controller, and after typing something It`s showing different values in console and in the view, can you tell me why?
PS. run your web browser console and you will see the difference.
example Plunker
When you change value, first ng-change is called, then $digest starts which will update filtrowane.
If you use such notations:
item in filtrowane = (tablica | filter:search)
do not use filtrowane in controller. Html should be view, so you should not declare any variables there, which you use in model (js).
Look here: http://plnkr.co/edit/QAHlbuZqWX4szglvMP87?p=preview
This code does same as yours, but filtering is done in javascript. A bit more complicated, but things are more clear. (it is also better for big arrays)
Use ng-blur instead of ng-change
<input type="text" ng-model="search" ng-blur="sprawdzFiltr()">
This is due to the ng-change is probably executed before the filter is applied, so the old value will be taken.

Subscribing to changes in siblings with Knockout.js

I'm using inheritance to implmenet a reuseable forms app.
Expression parameter can be dependent on one or more other numeric/constant ot other expression parameters (the relation is many to many so heirarchy wont work here). Once all my dependent parameters evaluated them self (calcualted if expression or validated if user input) I can now calculate my self.
I'm looking for a way to subscribe to my siblings but the problem is that during creation the sibling does not neccasarily exists yet.
I set up a small example on this Fiddle.
To see this not working in action lets change the values from the console
d.parameters()[0].value(10) // expecting parameter C to sum up to 20.
d.parameters()[2].value() // Nothing (this should also update ont he screen).
d.parameters()[1].value(20) // expecting parameter C to sum up to 30.
d.parameters()[2].value() // Still nothing.
So Ive tried sevral things but i think i'm barking up the wrong tree here.
Fetching the parent using ko.dataFor(document.body) or
fetching the object from the DOM using the same function.
I've played around with deferEvaluation as you can see in the code
to force KO to first create the parameters and then apply the
binding. seems to do nothing.
Tried creating a observableArray with the links to the params and a
computed based on the array but the problom remain.
Appreciate any help here.
Bonus question, without losing focus from the main one, somehing I cant explain going on on line 73.

Strange knockout js select option binding issue

Does anybody have a minute to take a look at a puzzling problem I'm having with Knockout JS and binding select lists?
The person's favourite color should be selected in the list by calling value: favColorId in the select list, rather than with the function-based call of value: favColorId(), something very strange is going on here, I've never used () in the past, it's also causing some other weird issues where it won't recall the value into the span (so changing the selected item does nothing).. I have tried recreating a simple sample as best I can demonstrating the issue.
http://jsfiddle.net/goneale/ph8Jw/
I have included my mapDictToArray() function but it simply converts a
javascript object into a key-value JS array. I wouldn't think that is
contributing to the problem.
Actually, that was part of the problem. The function returns a JavaScript array, not an observable array and therefor can't be used properly by Knockout. I've made the following changes to your code:
// The "mapDictToArray" makes a normal JS array, not a ko.observableArray();
// You can't simply "merge" a JS array with an observableArray(); you'll need
// some extra functionality for that: ko.utils.arrayPushAll()
// viewModel.colors(mapDictToArray(dict));
ko.utils.arrayPushAll(viewModel.colors(), mapDictToArray(dict));
// Apply the bindings *after* you've added the contents to the "colors" observable, in order to
// get the correct selected value
ko.applyBindings(viewModel);
That should do the trick (with the correct HTML without the () )!
JSFiddle.
UPDATE
I thought about my solution, but something wasn't correct. The only thing that was correct, was the part that you need to apply the bindings after you've added the contents of the colors observable. This is your fiddle, with that part moved down.
This works in your case, but you'll need to use the arrayPushAll method when there is already data inside the observableArray. This method merges, while you overwrite it when not using it (example with data inside the observable).

How can I get the index of an item added to a Backbone collection via fetch?

I’ve got a Backbone Collection. I’m using fetch({add:true}) to fetch new items from my server, and add them to the collection.
I’ve bound a listener function to the collection’s add event. I’d like that function to get the index at which the item was added to the collection.
Backbone’s documentation for Collection.add says “if you're a callback listening to a collection's "add" event, options.index will tell you the index at which the model is being added to the collection.”
I’ve logged the arguments that seem to be passed to my listener function to the console and had a look at them. As far as I can tell, the first argument is the item added, followed by a temporary collection object created to hold it when it came back from the server. I don’t seem to have an object with an index property.
How can I get the index at which the item was added to the collection?
To anybody reading this in the future, NOTE: since version 0.9.9, options.index is no longer set. From the changelog:
To improve the performance of add, options.index will no longer be set in the add event callback. collection.indexOf(model) can be used to retrieve the index of a model as necessary.
Check the third argument to your bind function, it should contain the index property
var c=new Backbone.Collection();
c.bind("add",function(model,collection,opts){
console.log(opts);
});
c.add({});
c.add({});
Edit : I just checked Backbone 0.5.3 and it would seem options.index is only available in version 0.9

Categories