Two way binding angularjs service bug - javascript

Take the following fiddle:
fiddle
Now in this code you will see the following line:
newList.forEach(function(y){
activeUsers.push(y);
});
This works perfectly fine. however change the code to:
activeUsers = newList;
And the code no longer works.
Can anyone tell me why this is happening and how i might fix it so the two way binding works?

That doesn't work because you change the reference. Your old $scope.activeUsers still points to the same old empty array.
After you change the reference, you'll have to get the new reference back from the factory. That's why changing the reference will cause you issues.
If you take the reference from the factory, like you do, then you'll have to keep working on that same array if you want all the bindings to work as you expect.

$scope.activeUsers = testFactory.getActiveUsers();
You assign the array ref to $scope.activeUsers. so if you push some element to activeUsers, $scope.activeUsers will change also.
activeUsers = newList;
Then if you do this, activeUsers point to another array ref, so at this time, $scope.activeUsers is not same as activeUsers.

Related

Detect array mutation

I have made a simple proof-of-concept Polymer 1.0 app that demonstrates my problem: JSBin.
In my problem, I am using array mutation methods to alter the array, which contains the list of shopping items.
However, this doesn't seem to work as intended. I do get a change in dom-repeat and when printing the length of the array. But I do not get the change event when I am printing the array itself nor when I wrap it in a function.
In short, why does this work?
<p>Number of items: [[list.length]]</p>
And why does this not work?
<p>Items inline: [[list]]</p>
<p>Observe function : [[_observe(list)]]</p>
Also, when I uncomment the following line (in the JSBin), things seem to work as indened. But I don't like it since it's a bit hackish.
app.notifyPath('list', app.list.slice());
I have stumbled upon the slice() fix by reading this issue: https://github.com/Polymer/polymer/issues/2068
EDIT
So, after reviewing the comments, the answer to the question "Is this by design" is YES. The array itself doesn't change (since it's only a reference), but it's property do change. That's why the slice() forces the reload since it creates a shallow copy.
However, one could argue whether this is OK. Yes, the variable list does not change per se. But putting [[list]] in the HTML code actually triggers toString(). And result of that function has changed.
I guess I'm stuck with piggybacking the length property for now...
As alluded to in the comments the notifyPath and slice calls are creating a shallow copy of the array and assigning a different reference back to the list variable - triggering an update of the binding. Without maintaining a separate (watchable) variable or messing around with object references, the only other workaround I can think of would be to piggy back on the list.length property instead of the list itself and pass that through some kind of "formatting" function. e.g.
<p>Items inline: [[format(list.length)]]</p>
app.format = function(){
return app.list.toString();
};
» Fiddle
As pointed out by #zb you could expand on this and make the function reusable with any array by passing the relevant variable as an argument too:
<p>Items inline: [[format(list, list.length)]]</p>
app.format = function(list){
return list.toString();
};
» Fiddle

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.

AngularJS - Change the $scope object

I have a very weird issue.
I have an object under the $scope
I using an angular.foreach loop but there is a problem.
when I'm trying to set a value depending on langKey(where langKey is 'en' or 'el') all the values are being updated by ingoring the langKey.
$scope.finalObject[langKey]['servicesElements'][itemKey]['name'] = something;
the problem still exists when I simply use the console in order to change the values from there.
I'm setting the value 'myCustomText' to the el version of the object
$scope.finalObject.el['servicesElements'][itemKey]['name'] = 'myCustomText'
BUT if i run this one
$scope.finalObject.en['servicesElements'][itemKey]['name']
it returns 'myCustomText' with no reason because what I changed was the el version not the en.
Is this normal? I'm totally stuck
Thank you in advance
Well guys,
The problem was that I had declared the two different objects with the same source.
$scope.finalObject.el.servicesElements = something;
and
$scope.finalObject.en.servicesElements = something
I didn't have seen that before, but the browser was behaving like I have typed
$scope.finalObject.en.servicesElements = $scope.finalObject.el.servicesElements = something
and in every change of the one the other was following.
(in php is called pointer)
The solution was to use the angular's copy function
http://docs.angularjs.org/api/angular.copy
So I simply used this SO answer Reset a model with angular.js did this
$scope.tmpVar = something;
$scope.finalObject.en.servicesElements = angular.copy($scope.tmpVar);
$scope.finalObject.el.servicesElements = angular.copy($scope.tmpVar);

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).

What's the correct way to use setValue on a TextField?

I have what appears to be a simple question, but I'm pretty stumped at this point. I'm working on some Ext.JS based UI code and I want to change the value of some text inside a form field.
The field is an ext.js.TextField.
I have code like this:
var foo = this.getForm().findField('myFooField');
console.log(foo);
foo.setValue("text different that is different from the default");
If I run this code, "foo" is definitely getting logged to the console, and it's a correct object populated with the values that I'd expect. However, the call to setValue doesn't seem to do anything.
I've put some trace calls before and after setValue to make sure it really does run, and everything seems to be happening without issue. It's just that the UI is not reflecting my change. I've tried calling "setRawValue" as well, but no difference.
Any suggestions? Much appreciated!
If you are using MVC probably you are trying to change value on render event of a window, for textfields the set value works only on afterRender event.
Your code looks right however I normally use a function like this
Ext.override(Ext.Container, {
setValue: function(c, v) {this.findById(c).setValue(v);},
getValue: function(c) {return this.findById(c).getValue();}
});
win.setValue('myFooField', 'Some text');
I am not sure why your code doesn't work. Check if the below code works.
Ext.getCmp('myFooField').setValue("text different that is different from the default");
Even if this isn't working, then probably you are having the code in wrong place.

Categories