AngularJS - ngmodel in ngrepeat not updating ('dotted' ngmodel) - angularjs

i'm trying to draw radioBoxes with angular array, and after that get value of checked radio, but model don't change its value you, can anyone help me with this ?
HTML part
<div ng-app>
<div ng-controller="CustomCtrl">
<label ng-repeat="user in users">
<input type="radio" name="radio" ng-model="radio" value="{{user.name}}" /> {{user.name}}
</label>
<br/>
{{radio}}
<br/>
Save
</div>
</div>
Angular Part
function CustomCtrl($scope) {
$scope.radio = "John";
$scope.users = [
{"name" : "John", "Year" : 18},
{"name" : "Tony", "Year" : 19}
];
$scope.saveTemplate = function() {
console.log($scope.radio);
};
}
you can see example here - http://jsfiddle.net/hgf37bo0/2/

you need to set $scope.radio to be an object like this:
$scope.radio = {
name: 'John'
}
and then access it from html like so:
<input type="radio" name="radio" ng-model="radio.name" value="{{user.name}}" />
here's a working jsfiddle
You can read up on why this is necessary in this answer
from angularjs docs:
Scope inheritance is normally straightforward, and you often don't even need to know it is happening... until you try 2-way data binding (i.e., form elements, ng-model) to a primitive (e.g., number, string, boolean) defined on the parent scope from inside the child scope. It doesn't work the way most people expect it should work. What happens is that the child scope gets its own property that hides/shadows the parent property of the same name. This is not something AngularJS is doing – this is how JavaScript prototypal inheritance works.
...
Having a '.' in your models will ensure that prototypal inheritance is in play. So, use
<input type="text" ng-model="someObj.prop1">
rather than
<input type="text" ng-model="prop1">
If you really want/need to use a primitive, there are two workarounds:
Use $parent.parentScopeProperty in the child scope. This will prevent
the child scope from creating its own property. Define a function on
the parent scope, and call it from the child, passing the primitive
value up to the parent (not always possible)

Related

ng-focus doesn't work with ng-include

I have a problem with ng-focus on ng-include elements. I use this part of code
<div ng-include="'template.tpl.html'" ng-controller="Ctrl"
ng-class="{'highlight':highlight==true,'nofocus':highlight==false}"></div>
and ng focus works fine when I have inside template.tpl.html regular DOM elements like:
<div class="form-group">
<label class="control-label">My label</label>
<div class="input-wrap">
<input type="text" name="Name" class="form-control"
ng-model="client.firstName" ng-disabled="displayMode != 'edit'"
ng-focus="highlight=true" ng-blur="highlight=false">
</div>
</div>
but, if I include another file in template.tpl.html it doesn't work anymore. For example if I apply in template.tpl.html the structure like below it won't work:
<div ng-include="'contacts/contacts-list.tpl.html'"></div>
Why ng-focus doesn't work on ng-include included in ng-include? Any tips on how to resolve this?
(Now that you have clarified your actual issue) As a continuation of the comment, ngInclude created a child scope of the provided scope, in your case child scope of child scope of Ctrl and well that does not matter since overall your wrapper is the Ctrl controller. But here you need to be careful while setting the scope property and expect the changes done from grandchild scope to be reflected in its grandparent scope. You have not even defined the properties in your controller, also even if you define them directly as scope.highlight = false the changes made to the property in the child or its child will not be reflected in the parent (though it will propagate down as a part of inheritance). You should remember scopes (except isolate scopes) are prototypically inherited, so in order to resolve this, you can use a property that holds the object reference which contains the property that needs to be modified, so that even if you change the value of property on that object from grandchild it will still reflect while accessing the same on the parent because they are all looking at the property on the same object reference
So in your controller initialize and object:-
.controller('MainCtrl', function($scope) {
$scope.settings = {};
});
Set the bindings accordingly in the main html:-
<div ng-include="'tmpl.html'" ng-controller="MainCtrl"
ng-class="{'highlight':settings.highlight,'nofocus':settings.highlight}"></div>
And in its grand child as well:-
<input type="text" name="Name" class="form-control"
ng-model="client.firstName"
ng-focus="settings.highlight=true" ng-blur="settings.highlight=false">
Plnkr
You wouldn't get a better explanation on angular scopes than this answer.

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.

why do two ng-repeats share same scope?

I have two divs with ng-repeat of the same list. But when I change the content of one list item from first div, the second div receives the same value. I thought ng-repeats had isolated scopes? How can I archieve isolation of the ng-repeats?
edit:
"In most cases, directives and scopes interact but do not create new instances of scope. However, some directives, such as ng-controller and ng-repeat, create new child scopes and attach the child scope to the corresponding DOM element."
http://docs.angularjs.org/guide/scope
<div ng-controller="MyCtrl">
<button ng-click="newitem()">add item </button>
<div ng-repeat="item in list">
<input ng-model="item.name" placeholder="Name*">
<input ng-model="item.lastname" placeholder="Last name*">
<input ng-model="item.username" placeholder="Username(Email)*">
</div>
here is another div with ng-repeat of the same list. why do they share scope?
<br>
<div ng-repeat="item in list">
<input ng-model="item.name" placeholder="Name*">
<input ng-model="item.lastname" placeholder="Last name*">
<input ng-model="item.username" placeholder="Username(Email)*">
</div>
js:
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.list = [];
$scope.newitem = function () {
$scope.list.push({name: "", lastname: "", username: ""});
}
}
http://jsfiddle.net/LZKq2/
I'll try to explain this in a different way than the other answers, though all answers are basically saying the same thing.
When you attach the controller to the div element, it creates an instance of the controller with the $scope attached to it, to which you add an array. The moment that you attach the array to the first child div and use ng-repeat, you get a child scope that belongs to the array. the second child div is not creating a new array but re-using an existing array which now already has a scope. Thus, items added into the array via the first div are reflected in the second div. It could not possibly function in any other way, as you only have one variable that you are tracking across the $scope. If, however, you had 2 separate lists, say $scope.list and $scope.list2, these 2 arrays would each have their own scope. see http://jsfiddle.net/zTE5j/2/
<div ng-controller="MyCtrl">
<button ng-click="newitem()">add item </button>
<div ng-repeat="item in list">
<input ng-model="item.name" placeholder="Name*">
<input ng-model="item.lastname" placeholder="Last name*">
<input ng-model="item.username" placeholder="Username(Email)*">
</div>
here is another div with ng-repeat of the same list. why do they share scope?
<br>
<div ng-repeat="item in list2">
<input ng-model="item.name" placeholder="Name*">
<input ng-model="item.lastname" placeholder="Last name*">
<input ng-model="item.username" placeholder="Username(Email)*">
</div>
</div>
controller:
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.list = [];
$scope.list2 = [];
$scope.newitem = function () {
$scope.list.push({name: "", lastname: "", username: ""});
$scope.list2.push({name: "", lastname: "", username: ""});
}
}
The new scopes are child scopes so although the scope is new, the properties on the scope are inherited from the parent. For example, if the parent has a list of items, then child scopes inherit the same list of items. Think of it as "pointers to the parent list." When you modify item "x" in the first list, item "x" is in a list on the scope. That list is inherited from the parent list, so modifying "item x" is the same as modifying that item in the parent list. Because the second list inherits from the parent, it also has the same reference to "item x" and therefore it will reflect the update.
This is demonstrated in this fiddle: http://jsfiddle.net/jeremylikness/xdzxb/
Note both lists are affected when you edit an item, but the third list isn't because it was created as a copy:
$scope.listNew = $scope.list.slice(0);
You'll need to explicitly create copies if you want the repeats to act on different versions of the list.
ng-repeat do creates new scope according to angularjs.
but do you have toString in a plain object ?
var a={};
if (a.toString) alert('1');// ( where the hell this toString came from ?)
this will alert 1 !!!
this is because of prototype inheritance.
your inline repeat scope has its own scope which SEEK FOR ITS PARENT SCOPE for data ( if not found).
why do they share scope?
Becuase they are both seeing the same viewmodel object , $scope which is created by the controller.

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

AngularJS passing data from a directive controller to another

I have a form, which with you can edit an image gallery, of course I've created a directive for it, like this:
galleryEdit.html
<div>
<form ng-submit="submit()">
<label>Headline:</label>
<input type="text" ng-model="gallery.headline" placeholder="Enter headline here" value=""/>
<label>channels:</label>
<channelselect></channelselect>
<input type="submit"/>
</form>
</div>
So, galleryEdit has another directive channelSelect, which with you can select a channel (not only for galleries)
channelselect.html
<div>
<select>
<option value="{{channel.shortCode}}">{{channel.name}}</option>
</select>
</div>
GalleryEdit has a controller, that passes data (called "gallery") for its directive, so its $scope has $scope.gallery property, which contains channel id: $scope.gallery.channel.
Since channelselect has different controller, that has its scope, this gallery.channel cannot be seen from that scope.
Is there any way to pass data from gallery to channel controller/directive ?
Using $scope.$parent is not a solution, since channelSelect should not know anything where the data is coming from.
You can set up bi-directional binding between your galleryEdit directive's scope and your channelselect directive's scope.
In your channelselect directive's definition, you can do something like the following:
directive('channelselect', [function () {
...
scope: {channel: '='}
...
}])
This will create an isolated scope for your channelselect directive, and will let you use the channel attribute on your <channelselect> tag to set up a bi-directional binding to its parent scope.
So now you can do this in galleryEdit.html:
<channelselect channel="gallery.channel"></channelselect>
Now channelselect's $scope.channel will be bound to galleryEdit's $scope.gallery.channel.
See the Directive Definition Object section of AngularJS's Directives guide for more details on isolated scopes.

Resources