Angular $scope set to another $scope value not working - javascript

I am trying to give one $scope variable the value of another $scope variable. Can someone tell me what is going wrong? Take a look at the simple plunker for details:
http://plnkr.co/edit/TlKnd2fM5ajrlkKKhKZ1?p=preview
I know I am missing a fundamental concept in the way $scope works, but I can't pinpoint what it is. Somebody slap me and give me that 'Ahaaaa' moment if you don't mind.

The problem is that what you assign to the greeting property does not get reevaluated when username changes. greeting gets stuck with the initial (blank) value of username. You could set up a watch on username and modify greeting when username changes, or you could change the view:
<div ng-controller="Parent">
{{username}} {{greeting}}
<!-- ... -->
</div>
And don't use username when assigning to greeting:
$scope.greeting = 'is so confused.';
Here's an updated example.

There is nothing wrong with what you are doing, but you can't expect greeting to get updated every time username changes since the binding (that creates a $watch) is done in greeting, which is a string. So everytime a $digest loop occurs it will just re evaluate your variable greeting to the same result ("is so confused.").
You need to bind the property you want to maintain updated like this:
plunker

Related

Angular radio ng-change works only first time

I can't understand why angular ng-change function are called only in first click. In this example
http://jsfiddle.net/ZPcSe/5/
function is called every time when i change current radio selection, but in my code something is wrong
http://jsfiddle.net/4jL3u8ko/1/
Can someone change my code to work like first example, and explain why it isn't working?
Great question.
This is not an answer but one may call this explanations to answers and any further problems that may occur. And this happens quite often, so its important to understand. The answer given by #Victor is ok and the comment of #Atias is also helpful.
Explanation -
Simple explanation : ng-repeat forms child scope.
Little detailed :
So your application has 3 scopes (or may increase depending on the number of values in $scope.radioButtons). Let me name them - parentScope(main scope), childScope1(scope of first element of ng-repeat) and childScope2(scope of second element of ng-repeat).
Parent scope variables : calledFunctions(array), radioButtons(object) and newValue(function)
ChildScope1 variables : name(assigned a literal at the start), val(assigned an object at start) and value(it has no value, or undefined)
ChildScope2 variables : name(assigned a literal at the start), val(assigned an object at start) and value(it has no value, or undefined)
What happens when you click on the radio button of childScope1(for first time):
ChildScope1.value = ChildScope1.name or ChildScope1.value= "Radio1"; the ng-change directive checks if this scope's model has been changed? Yes, as it was undefined and now it has a literal("Radio1")!! So call ChildScope1.newValue(), which obviously is not present. Therefore now look for parent- call parentScope.newValue(). This is present, so execute it.
keep in mind that ChildScope1.value= "Radio1";
After clicking on other radio buttons......
Now lets click 2nd time on ChildScope1's radio button. After clicking it- ChildScope1.value = ChildScope1.name or ChildScope1.value= "Radio1"; the ng-change directive checks if this scope's model has been changed??? No!! Because it still contains the same literal vaule as before, so do not even look for ChildScope1.newValue() or ParentScope.newValue() function.
Now same thing happens with ChildScope2.
Hope this explains why your fiddle works like a one time binding, or how #Victor or #Atias are correct.
Simply the solution is - The ng-model of ChildScope1 or ChildScope2 or any other child scopes, should point to a variable of parent scope. So you can use $parent or make an object in parent scope(main scope) with a property( eg.- ParentVal={ChildVal = ""};). And in ng-model inside ng-repeat- write ng-model=ParentVal.ChildVal.
Sorry for my poor english and please pardon my spelling mistakes if there is any.
Thanks
ng-model is tricky. You should always, always have a dot in your models, or you get this kind of problem where you are creating several models and you think you only have one.
As a quick fix, use $parent.value instead of just value in your ng-model and ng-change.
As a good fix, have a proper model object in the scope, instead of storing values directly in the scope:
$scope.model = {};
ng-model="model.radiosValue"
As an even better fix, use the controllerAs pattern and use that object as the view model.

scope variable inside object does not get updated

I have an issue where my $scope.searchVal variable updates, but if I assign it inside an object, it doesn't seem to update at all.
See below:
<div ng-controller="MyCtrl">
<div>{{searchVal}}</div>
<div>{{searchFilter}}</div>
<div>
<input ng-model="searchVal"/>
</div>
</div>
See the JSFiddle
If I type in the input, the first div's value updates properly for searchVal, but the searchFilter object that contains $scope.searchVal as a value is set to the original value of '' and does not update accordingly.
I've considered (and tried) updating the whole object everytime I need it by calling a function, but this seems really hacky to me. Is there a simple way to get this done? Am I missing something?
What you have to is $watch the value from the scope something like:
Online Demo
$scope.$watch('searchVal',function(newVal, oldVal){
$scope.searchFilter.search = newVal;
});
It isn't as straighforward as it seems since angular has no way of knowing whether you want the dynamic binding for the property or not.
You can achieve what you are trying to do using $watch service. Put a watch on the searchVal & use it to detect changes & update the object property accordingly.
Please put $watch . It will always watch the value change of variable
$scope.$watch('searchVal',function(newVal, oldVal){
$scope.searchFilter.search = newVal;
});
updated fiddle http://jsfiddle.net/be6s1eLo/3/

AngularJS Get current factory/service name

Ola!
I was just playing around with angular's factories and services and I just noticed
that I can't get the current name of the factory/service.
At least I couldn't get any resources about that.
For example so its a bit more clear I have a factory, like this;
.factory('GuessImAFactory', [function() {
var factoryName = this.yadayada.name; //<- This actually doesn't work,
//if you haven't guessed
//<--Some other code goes here-->
return something;
}])
So the question does anyone know the trick how to get the name of it?
I don't think this is possible. In callback function you can't get actual instance of factory since you are defining it right in that place. In other works, it's not yet created.
However, simple workaround for this would be to hard code it.. Since you probably won't have dynamic factories, you could just simply say
var factoryName = 'GuessImAFactory';
and use it if needed.
Try this one: factoryObject.__proto__.constructor.name

`ng-model` of AngularStrap `bs-typeahead` not available in scope?

I am running into an issue with the value of ng-model, applied to an element using AngularStrap's bs-typeahead, is not accessible within scope. It is however viable from a {{ var }} within the HTML.
I have the following HTML:
<input type="text" placeholder="add a destination" ng-options="item as item for item in modelTypeahead" ng-model="selectedDestination" bs-typeahead data-template="templates/SrcDstTypeaheadTemplate.html">
I initialize the variable in my controller:
$scope.selectedDestination = "";
Placing a {{ selectedDestination }} elsewhere within the HTML works as expected.
However, when I do a console.log($scope.selectedDestination); within my controller it comes out as an empty string.
If I update my initialization to be something, for example:
$scope.selectedDestination = "abc123";
... both the <input> and the {{ selectedDestination }} update appropriately. My console.log will also spit out the set value. However, if I update the typeahead the {{ selectDestination }} will update but my console.log will spit out 'abc123' still.
Is there a scope issue that I am missing? I don't understand how {{ selectedDestination }} is putting out the correct string but the console.log is putting out something different. It would almost seem my binding is one-way, but AngularStrap's bs-typeahead should be two-way (per all the examples).
Where are you doing console.log? You would have to make sure that the value has changed before you do that for the value to show up, you could do:
$scope.watch('selectedDestination', function() {
console.log($scope.selectedDestination);
});
I'm not sure if you're still running into any issues with this, but I found a solution to the exact same problem when I ran into it just recently. I'm almost positive that its a scope issue or apply failure within the AngularStrap stuff, but I wouldn't know where to start looking.
Really, I'm not educated enough to give you the exact reasons that this works, but this is what you do:
(1) You change the variable to an object.
when you put the model and watch on an object instead of a top layer variable, it works better through layers of directives. Don't ask me why....
(2) Use a deep watch on the object you just created.
When you change it to an object, you need to use a deep watch on the variable or the $apply and $digest won't pick up any changes. This is because by default the value will be checked for "reference" equality instead of "value" equality. This breaks because the object's "reference" doesn't change, only its values. But be careful using this deep comparison because the extra effort can cause a lot of overhead.
Here's an example in use with AngularStrap's typeahead:
$scope.selectedDestination = {};
~~~
<input type="text" placeholder="add a destination" ng-options="item as item for item in modelTypeahead" ng-model="selectedDestination.destination" bs-typeahead data-template="templates/SrcDstTypeaheadTemplate.html">
~~~
$scope.$watch('selectedDestination', function(value) {
console.log('selectedDestination', $scope.subComponent);
}, true); //here we need to tell the watch to do a deep watch
EDIT I've traced my issues back to a few things, but part of it was the $render function. I'll keep looking into it. Good luck!

Why does one AngularJS service bind work but the other doesn't

If you take the following Plunkr you will see a simple service - increments a count and it gets reported to the user.
What I am trying to understand is why this works (the increment is reported to the user on a click) - binding to the function in the view:
From the HTML
<p> This is my countService variable : {{countService()}}</p>
From the controller
$scope.countService = testService.getCount
And why this Doesn't work - binding the function to the scope:
From the HTML
<p> This is my countService variable : {{countService}}</p>
From the controller
$scope.countService = testService.getCount()
Ultimately we're binding to a function in the service, though the second one doesn't bind the new value.
A clear, easy to understand, explanation would be great :)
In the first version you bind directly to the function so angular checks if the functions output has changed. In the second version you only call the function once when the scope is created and set countService to that value. Since countService now is a variable that has nothing to do with the counting function its value wont reflec the value returned from that function.

Categories

Resources