Scope variable is changing unexpected manner Angular JS - angularjs

I am a beginner in AngularJS. Recently tried out below code.
HTML Tag:
<div ng-app="myApp">
<input type="text" ng-model="message" />
<h1>{{ message }}</h1>
<div ng-controller="ctrlOne">
<input type="text" ng-model="message" />
<h1>{{ message }}</h1>
</div>
<div ng-controller="ctrlTwo">
<input type="text" ng-model="message" />
<h1>{{ message }}</h1>
</div>
</div>
JS Script:
var app = angular.module("myApp", []);
app.controller("ctrlOne", function($scope) {
console.dir($scope);
});
app.controller("ctrlTwo", function($scope) {
console.dir($scope);
});
If you type in the text area. Each output print is unique. Even though I have used common variable to the $scope element.
Can any one please explain,
1. what is happening internally?
2. How angular is handling this scope?
If you can help with step wise advice explaining, so that it is easy for beginner like us to understand.
Your time spent on this highly appreciated. Thanks in advance.
Please find JSFIDDLE Link Below:
Code Snippet example on $scope
Please check the console. Its is showing undefined.

Even though you have used a common variable, but both of them are under the scope of different controller.
One is under the scope of controller ctrlone and other is under the scope of controller ctrltwo.
When you create a controller, angular creates a separate scope pertaining to that controller alone. So even if the names of variables are same but if they are defined on two different scope, they will have unique values.
However, if you want to have a variable with same value in both controller, then you will have to define that variable on $rootScope because $rootScope is created once per app.
Inside your controller, you can retrieve the value like this:
console.log($scope.message);
This will give you the value of message as you typed in the input box.

Related

Why does angular keep showing false when input is touched?

I am new to angular. I have set up the following code to see if an input field has been touched. However when i type on the input field. It doesn't change. Just keeps showing false.
Not sure what I am doing wrong here. Any help would be really appreciated it.
<div ng-app='myApp' ng-form name="myForm">
<input type='text' name='address' ng-model="address" id='address'>
<h1> {{myForm.address.$touched}}</h1>
</div>
<script>
var app = angular.module("myApp",[]);
</script>
$touched in AngularJS jargon doesn't mean "was the value changed". That's $dirty's role.
$touched in AngularJS means that the field was blurred (that is, the field isn't selected anymore).
See it in action at plnkr.co.

How we set to ng-model variable to parent controller in nested controllers scope

I have one ng-controller nested in another controllers scope.
I want to set scope variable in nested controller scope, to parent controller.
I have view:
<div ng-controller="MyCtrl">
<input type="text" ng-model="name"/>
<div ng-controller="CountryDataController">
<angucomplete
(...)
selectedObject="country"/>
</div>
</div>
which is part of the form.
Then on form submit i want to send ng-models from MyCtrl ( name,country) doing:
fields: {name: $scope.name,
country: $scope.country,
},
How can i tell angular, that selectedObject model belongs to MyCtrl, and not CountryDataController.
I tried
selectedObject="MyCtrl.country"
selectedObject="country[MyCtrl]"
but without effects.
selectedObject in angucomplete works like ng-model.
Also I don't want to rewrite logic from CountryDataController to MyCtrl, because in first i have fields for autocomplete and in second file uploading.
Is there any convention for this?
The answer is:
selectedobject="$parent.country"
You can use $parent, but if you move your HTML or eventually add another controller it between it will break.
The correct way to do that is to use the controller as syntax, as shown below:
<!-- use topCtrl to access this controller scope -->
<div ng-controller="MyCtrl as topCtrl">
<input type="text" ng-model="name"/>
<!-- use countryCtrl to access this controller scope -->
<div ng-controller="CountryDataController as countryCtrl">
<angucomplete
(...)
selectedObject="topCtrl.country"/>
</div>
</div>

How get form by name in $scope?

How to get form by name in $scope?
Test example:
<div ng-controller="solod">
<form name="good_f">
<input type="text" name="super">
</form>
</div>
<script>
function solod($scope){
console.log($scope.good_f) //undefined
}
</script>
Is it possible?
Thank you
You usually don't want the controller to access the form like this, that's coupling the controller to the structure of the view too tightly. Instead, pass the form to the controller like this...
<div ng-controller="solod">
<form name="good_f" ng-submit="submit(good_f)">
<input type="text" name="super">
</form>
</div>
<script>
function solod($scope){
$scope.submit = function(theForm){
console.log(theForm)// not undefined
console.log($scope.good_f) // will exist now also
};
// do stuff in a watch
$scope.$watch("good_f", function(formVal){ console.log(formVal);});
}
</script>
Otherwise, if you just want to track the value of the text input, give it an ng-model
Edit:
On further research, $scope will have good_f as a property, just not when you're logging it in the constructor. You could set up a watch on good_f if you wanted, but I still think you should pass it in.
name (optional) string Name of the form. If specified, the form
controller will be published into related scope, under this name.
https://docs.angularjs.org/api/ng/directive/form
Another possible way is to use ng-form, this will help you to access the form via scope easily.
<div ng-controller="solod">
<ng-form name="good_f">
<input type="text" name="super">
</ng-form>
</div>
Script code in your controller:
EDIT:
As JeremyWeir mentioned, to solve your problem you can use $timeout service of angularjs
function solod($scope){
$timeout(function(){
console.log($scope.good_f);
});
}
Caution: Don't use this - seriously
Angular is not jQuery.
As par as your question is concerned you can use $element in your controller(if you are not concrete with the $scope usage for this use case) -
myApp.controller("myCtrl", function($scope, $element){
alert($element.find('form').attr('name'));
$scope.myFormName = $element.find('form').attr('name');
});
PLNKR DEMO

AngularJs multiple instances and nested controller

I got confused a bit about whether can we create multiple instance of controller and that to in nested form for eg -
<div ng-controller="abc">
<form ng-submit="call()">
<input type=text ng-model="content"/>
</form>
<div ng-controller = "abc">
<form ng-submit="call()">
<input type=text ng-model="content"/>
</form>
</div>
</div>
i just want to know that if i use the same model with other instance of controller, so model value would be same or different. Similar to static variable ?
i just want to know that if i use the same model with other instance
of controller, so model value would be same or different. Similar to
static variable ?
All declarations of ng-controller create a new instance of the controller. So, if you had two instances side by side, like this:
<div ng-controller="abc">
<input type=text ng-model="content"/>
</div>
<div ng-controller="abc">
<input type=text ng-model="content"/>
</div>
plunker
then, all of the $scope properties of each would be completely independent.
When a ng-controller is nested, then its scope inherits the parent controller's scope. So for this you'd expect that content refers to the same scope property:
<div ng-controller="abc">
<input type=text ng-model="content"/>
<div ng-controller="abc">
<input type=text ng-model="content"/>
</div>
</div>
plunker
However, since content is not defined directly in the controller something strange happens. If you fill in the parent input first. Both, inputs become bound to the same scope property. However, if you fill in the child input first, they are independent!
This can be confusing until you understand that Angular is being lazy when it creates the property on the scope. content is null at first on both scopes. It is only when it has a value that it will inherit.
So, what do you do if you want to keep things separate? Add an initial value to a $scope property inside the controller:
app.controller('abc', function($scope) {
$scope.content = '';
});
plunker
This way, each separate controller instance is initialized with its own content property.
Hope this helps.

How to pass custom directive name dynamically in class attribute of div tag?

I am very new to AngularJS. I have made a custom directive user and I want to call it dynamically in class attribute by using a variable.
e.g. $scope.dirName = "user";
When i use this variable in below code:
<div class = {{dirName}}></div>
Its result must show two input fields with specified values. But it is not doing so. When I replace {{dirName}} with user. It is working fine, means two input fields are shown with values as specified. Can anybody tell, what mistake I am doing?
This is index.html
<div ng-controller = "Ctrl">
<form name = "myForm">
<div class = {{dirName}}></div>
<hr>
<tt>userName : {{user}}</tt>
</form>
This is script.js
<pre>var app = angular.module('App',[]);
app.controller('Ctrl', function($scope){
$scope.user = {name:'adya',last:'Rajput'};
$scope.dirName = "user";
});
app.directive('user',function(){
return{
restrict:'C',
templateUrl:'template.html'
};
});</pre>
template.html contains:
UserName : <input type='text' name='userName' ng-model='user.name' required>
LastName : <input type='text' name='lastName' ng-model='user.last'>
Unfortunately, you cannot save names of directives in string variables and access them in the HTML. You can, however, save a string in a variable in $scope and use ng-switch to select the correct directive:
<div ng-switch="dirName">
<div ng-switch-when="ng-user">
<div ng-user></div>
</div>
<div ng-switch-when="...">
...
</div>
</div>
However, now it might be better to use something more descriptive than ng-user to switch over.
Sidenote: Do not use ng- prefix in your own directives. Angular uses that prefix so that it does not collide with other namespaces. You should use your own prefix for your directives.
Update: For the updated question as to why <div class="{{dirName}}"></div> does not work, it happens because angular $compiles the directive only once. If you first $interpolate the content of the template (which will replace {{dirName}} with ng-user) and then explicitly $compile it before entering it in the HTML, it should work.

Resources