AngularJs multiple instances and nested controller - angularjs

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.

Related

Isolate and shared scope same time in directive AngularJS

New to Angular so not sure if I ask my question the right way.
So I have form.
<form ng-controller="myController" action="" method="get">
<div myDirective>
<input ng-model="question.sex" value="male" type="radio">
<input ng-model="question.sex" value="female" type="radio">
<button ng-click="log(LogThisQuestionAnsware())"></button>
</div>
<div myDirective>
<input ng-model="question.agree" value="no" type="radio">
<input ng-model="question.agree" value="yes" type="radio">\
<button ng-click="log(LogThisQuestionAnsware())"></button>
</div>
</form>
So my goal is to log current "question" answer. on button click.
How can I access local question in myDirective separate from my second directive and have in controller scope too.
--[ Edit: ]--
Ok this is pretty much my scenario. http://jsfiddle.net/y5esnm09/5
Each button have to log its own directive value not both radio values if they are selected.
If I correctly understood your question, you want both directive instances to bind to the same question object, but have their scopes separate from eachother:
Set up a two way data binding between your directive and your controller, e.g.:
<div my-directive question="question">
<!-- the rest -->
angular.module('your.module').directive('myDirective', function() {
return {
scope: question: '=',
//other props
}
This will ensure that both directives bind to the same question object but have their own separate scopes.
An alternative would be to set the scope property to true, that way they will both create a child scope of your controller.
EDIT: Fiddle demonstrating two way binding:
http://jsfiddle.net/L0eqf4qe/
PS: I converted myDirective to my-directive, angular will translate the snake-case to camelCase for you.

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>

AngularJs - model value does not reflect on ui in nested controllers case

I am using angularjs for one of the my module in application. I want to update UI of various locations on page, so that all ui components will work synchronously as the model value changes.
here is my html-
<fieldset ng-controller="controller1" >
<legend>Divs with common controller</legend>
<div style="background-color:#eee;padding:3px;">
<input type="text" ng-model="Model1" />
</div>
<div style="background-color:#eee;padding:3px;">
<input type="text" ng-model="Model1" />
</div>
</fieldset>
<fieldset ng-controller="controller1" >
<legend>Divs with common controller</legend>
<div style="background-color:#eee;padding:3px;" ng-controller="controller2">
<input type="text" ng-model="Model1" />
<input type="text" ng-model="Model2" />
</div>
<div style="background-color:#eee;padding:3px;">
<input type="text" ng-model="Model1" />
</div>
</fieldset>
and my javascript -
var testApp = angular.module('testApp',[]);
var mainApp = angular.module('mainApp',['testApp']);
testApp.controller("controller1",['$scope',function($scope){
$scope.Model1 = "testText";
}]);
testApp.controller("controller2",['$scope',function($scope){
$scope.Model2 = "testText2";
}]);
angular.bootstrap(document, ['mainApp']);
In the html for first fieldset it is working properly. But in second fieldset it is not. So can anyone please tell me how do i achieve the functionality of first fieldset in second fieldset.
Thanks.
use $rootScope instead of $scope
Can you use ng-controller="controller2" to particular input.
Try this
<div style="background-color:#eee;padding:3px;">
<input type="text" ng-model="Model1" />
<input type="text" ng-model="Model2" ng-controller="controller2" />
</div>
It doesn't work because you create 2 seperate scopes/instances for controller1
<div>
// Root scope
<div ng-controller="controller1">
// Child scope A
// scope = new controller1();
</div>
<div ng-controller="controller1">
// Child scope B
// scope = new controller1();
</div>
</div>
You can solve this problem by using the $rootScope directly or by creating a service. The recommended way is to avoid $rootScope whenever possible and use a service instead.
Value is probably the easiest way to create a service. Note that you can also use .service or .factory. Read more in the documentation about services.
testApp.value('myValue', {
data: 'testText'
});
I'm using an object here so we can use this as a reference to the value, this is important for sharing data between controllers. If you want to know why then read more about reference & value types.
Now inject this service into your controller and use this data instead:
testApp.controller("controller1",['$scope', 'myValue',function($scope, myValue){
$scope.Model1 = myValue;
}]);
On the view we need to update the bindings to the reference of the service:
<input type="text" ng-model="Model1.data" />
JSFIDDLE
USE THE DOT! ng-model without "." is bad.
Please read this
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
The issue is fully described there.

ng-model not updating with radio button

I'm getting a problem with angular and I'm not understanding what the problem may be:
thats a div:
<div ng-controller="CountrySelectorController">
Selected Countryid = {{countryid}}
<div class="radio" ng-repeat="country in countries">
<input type="radio" name="countryOptions" ng-model="countryid" value={{country.countryid}} ng-checked="countryid == country.countryid" /><span style="margin-left:10px;">{{country.countryid}}.{{country.name}}</span>
</label>
</div>
</div>
thats my controller:
app.controller('CountrySelectorController', function($scope, $rootScope){
$scope.countryid = 1;
});
the problems I'm getting:
-Selected Countryid=1 appears at start . Although I'm selecting different countries, the model is not updating
ng-repeat creates its own scope, which is not what you want to bind the ng-model to. You want to bind ng-model to the controller's scope (which is the parent scope of the ng-repeat).
Use $parent to go up a level to the correct scope. Also, don't use ng-checked.
ng-model="$parent.countryid"
Demo

Model not updated when view changes

I have a form for creating new records in a partial which I load in my main view like this
<div ng-controller="NewProductController">
<ng-include src=" 'views/partials/product-form.html' "></ng-include>
</div>
In the form, I have some input fields
..
<input ng-model="cip" type="text" id="cip" class="form-control" placeholder="Enter the CIP" autofocus="autofocus"/>
<input ng-model="name" type="text" id="name" class="form-control" placeholder="Enter the name" />
And in my controller, I'm sending a POST request with the values of the input fields:
...
.controller('NewProductController', function(Product, $scope) {
$scope.create = function () {
Product.create( {'cip': $scope.cip,
'name': $scope.name,
'dosage': $scope.dosage,
...
});
};
The problem is that when the values of the input fields change, it is not reflected in the controller ($scope.cip and $scope.name are undefined unless I initialized them with some value) but when $scope.cip and $scope.name are changed in the controller, the changes are correctly reflected in the view.
I thought that kind of updates are automatic or am I missing something ?
The reason why this is happening because ng-include creates a child scope. Since you are managing the model fields in the child scope i.e inside the template html, the fields are not available on the parent scope, where your controller is defined.
To fix this issue first and foremost thing that you need to do would be to create a obj such as product and define it on the controller NewProductController scope.
$scope.product={};
The template then should bind to sub properties of this product object.
<input ng-model="product.cip" type="text" id="cip" class="form-control" placeholder="Enter the CIP" autofocus="autofocus"/>
Now your changes would be available in the parent product object.
You can improve it a bit by passing the product object using ng-init like this
<ng-include src=" 'views/partials/product-form.html' " ng-init='model=product'></ng-include>
Now your template input fields change to
<input ng-model="cip" type="text" id="model.cip" class="form-control" placeholder="Enter the CIP" autofocus="autofocus"/>
Advantage
You template is not dependent on the structure of parent model class. Dependency is explicit. The template becomes more reusable as it clearly defines the model it works with, like in your case the template works with Product model.
For the sake of completeness of the answer i must link to this must read article, Understanding Scopes

Resources