strange angularJs variable behavior - javascript

Kindly explain me this behavior. I have decalred 2 variables.
$scope.data = {'value' : 123};
$scope.v1 = $scope.data;
Now if i change the value
$scope.data.value = 2;
and try to print
alert('old value is '+$scope.v1.value);
It gives me output as 2 whereas I think it should give me value as 123.
Kindly tell me that is it the same behavior like Java where one variable has different instances and change in one reflects in another ?

As you're guessing you are not creating a new object when you assign $scope.data to $scope.v1. You're just "pointing" $scope.v1 to $scope.data which implies that any change that you do to $scope.data will be reflected also in $scope.v1.
If you want to have different elements you should make a copy of the object. Look at angular.copy

Yes. You want to use angular.copy() to solve your current issue.
Anyways this all happens because of making one Object equal to another is assigning a reference; not creating a copy.

Related

Having trouble with assigning scope to variable to manipulate

Attempting to assign a scope object to a JavaScript variable to do minor manipulation before sending to my API. However, any changes made to the JavaScript variable change the scope object.
var recruitingCallListOutput = $scope.RecrutingCallingList.Recruit;
// manipulation of recruitingCallListOutput
The manipulation actually still updates the scope object which is not desired. Feel I am not understanding something in AngularJS correctly. Is there a way to grab the data and detach it from the scope?
In your example, recruitingCallListOutput is a reference to $scope.RecrutingCallingList.Recruit (see https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0 for more detail.) You will want to make a copy of $scope.RecrutingCallingList.Recruit.
If Recruit is a shallow object, meaning no nested objects (property values are primitives only), you can simply do
var recruitingCallListOutput = Object.assign({}, $scope.RecrutingCallingList.Recruit);
If you have nested objects/arrays as property values, you'll need to deep copy. It's been a while since I have been in the angular world, but
var recruitingCallListOutput = angular.copy($scope.RecrutingCallingList.Recruit)
you could actually use angular.copy in both examples.
This is nothing to do with AngularJS. It's Javascript, and it's expected behaviour.
For example, if you open the browser console (F12->Console) right now and run this:
var foo = {x:1};
var copy=foo;
copy.x=2;
console.log(foo.x);
you will see {x:2} printed out.
This is the same behaviour you would expected for any object reference in Javascript, C#, Java, etc. Because you are making a reference and not a copy, any changes to the reference are actually changes to the original.
The simplest way to solve this problem in your case is to copy the values you are interested in from the item in question into a totally separate object and modify that copy.
e.g.
var recruitingCallListOutput = {
name: $scope.RecrutingCallingList.Recruit.name,
age:$scope.RecrutingCallingList.Recruit.age,
modifiedSomething: $scope.RecrutingCallingList.Recruit.something + 42 //or whatever modifications you need to make
...and so on.
};
There are ways to "clone" an object in Javascript but unless your object is really really complex I would be careful. And consider if you really need all of the properties of the original object anyway, perhaps you only need to send some of them to your backend.

Why when a variable is used within another variable, its value its fixed to first declaration?

In the following code, I would expect the output to be "text something different" but instead it is "text something".
var dynamic = "something";
var thistext = "text " + dynamic;
dynamic = "something different";
console.log(thistext);
Changing the variable "dynamic" after declaring the variable "thistext", which contains it, does not change the value of "dynamic" within the "thistext".
I am sure this is something basic, but I think I do not know this rule or the best way to avoid this situation.
A Jsfiddle:
https://jsfiddle.net/k5wwpvgt/
Why when a variable is used within another variable, its value is fixed to first declaration?
You are not "using a variable within another variable". You are using a variable in an expression, the evaluated result of which happens to be being assigned to another variable. Expressions are evaluated when they are encountered, with the current values of any variables within them. There's no particular word for this behavior, since it is so fundamental to JS (and all other imperative/procedural languages).
Expressions are not dynamic definitions of calculations which are magically kept updated when their inputs change, much less magically updating variables to which the expression happened to have been assigned in the past. There is a word for such dynamic definitions of calculations: they are called functions. If you want some calculation to be dynamically redone when its inputs change, then write it as a function and call it when you need to recalculate, and if you want to (re-)assign the result of the invocation (the return value) to a variable, then do so.
Is there a way to contain a reference to a variable within another variable, and not the value of the variable when the assignment was evaluated?
Again, you're confusing variables and expressions and possibly functions. A variable is merely a box, referring to some value. It maintains no record of when or how it was assigned to, or what expression was used to calculate the value being assigned to it, nor does it have any means of automatically updating itself. Being a box, a variable cannot "contain a reference to another variable".
the best way to avoid this situation.
This is not a "situation" to be "avoided". It is the basic behavior of JavaScript.
Indeed, as others pointed out, this is expected behaviour; to do what you want, you could use a function:
var dynamic = "something";
var thistext = () => "text " + dynamic;
dynamic = "something different";
console.log(thistext());
Mind the diferences! Now thistext is a function, you must call it with (), and it gets evaluated every time.
thistext does not "contain" the variable dynamic, it contains the contents of that variable as it was at the time the expression was evaluated.
When browser will compile your javascript it will look something like
var dynamic = undefined;
var thisText = undefined;
dynamic = "something";
thistext = "text " + dynamic;
dynamic = "something different";
console.log(thistext);
when you are logging the value, you are just logging the value of thisText, which is populated when the value of dynamic is "something".
If you do the same operation after changing dynamic value you will see your desired result.
Hope this helps.

Two way binding angularjs service bug

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.

unbinding scope property in angular

Is there a way to unbind the reference when we are assigning values from scope properties?
For example I have $scope.X and $scope.Y. At some point in my function I want to assign the value of $scope.Y at that time to $scope.X:
$scope.X = $scope.Y
However, whenever scope.Y changes, looks like $scope.X changes too. Is there a way to avoid the chain? I just want to assign the value of $scope.Y once.
I tried using angular copy but it didn't work:
$scope.X = angular.copy([$scope.Y])[0];
Thanks
angular.copy should produce a clone of the object. There are a few other methods that may be perform better, see What is the most efficient way to deep clone an object in JavaScript? . I already use lodash for other stuff in my site so I use the _.cloneDeep method.

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

Categories