Angular.JS: why can't the inputs be edited? - angularjs

This is a strange problem. The code is simple:
HTML code:
<body ng-controller="MainCtrl">
<ul ng-repeat="name in names">
<input type="text" ng-model="name" />
</ul>
</body>
Angular code:
app.controller('MainCtrl', function($scope) {
$scope.names = ["aaa","bbb","ccc"];
});
The live demo url is: http://plnkr.co/edit/2QFgRooeFUTgJOo223k9?p=preview
I do not understand why the input controls can not be edited, I can't type new characters or delete characters.

This is a common issue due to scope inheritance . Each of your names is a primitive so ng-repeat makes it's own scope item that is not connected to original, however if each names is an object ng-repeat scope item will be a reference to original object
[{name:"aaa"},{name:"bbb"},{name:"ccc"}];
Always use a dot in ng-model is a helpful rule of thumb
<div ng-repeat="item in names">
<input type="text" ng-model="item.name"/>
</div>
Working Plunker
Read this article on angular github wiki for detailed explanaton:
https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance

Angular 'fixed' this in 1.1 with the track by $index. No need to change your model.
<div ng-repeat="item in names track by $index">
<input type="text" ng-model="names[$index]" />
</div>
Plunker here

Late answer, but you should also be careful of typos, that angular will not warn you about:
<div ng-repeat="item in names track by $index" ng=if="names[$index] = 'John'">
<input type="text" ng-model="names[$index]" />
</div>
Note the single equals in the ng-if, that will not cause a warning or error, but the text will also be read only. Quite a hard one to spot if you are reading quickly.
It of course should be:
<div ng-repeat="item in names track by $index" ng-if="names[$index] == 'John'">
<input type="text" ng-model="names[$index]" />
</div>

Related

Can ng-model replace Ids?

Is there a way to avoid IDs while creating elements i.e. using ng-model it is easier to validate form fields and other stuff?
<div ng-repeat="x in TestData">
<input type="text" id="nameField-{{$index}}"/>
</div>
The above code will display the number of input boxes equal to the length of the TestData array where every text box will have a unique id "nameField-0", "nameField-1" and so on, using these IDs we can take the textbox values, validate the fields etc.
<div ng-repeat="x in TestData">
<input type="text" ng-model=""/> <!-- what shall be done here to have unique IDs -->
</div>
Although going with IDs is working fine for me but as far as I can understand If I use IDs then that will not be a pure angular way (or IDs cannot be replaced by mg-models), correct me If I am wrong.
You don't need to grab element with id/name/etc. You can use ng-model to bind your values and ng-pattern to validate them.
<div ng-repeat="x in testData">
<ng-form name="tForm">
<input type="text" name="tInput" ng-model="x.name" ng-pattern="/^[A-Z]*$/" />
<span ng-if="tForm.tInput.$error.pattern" style="color:red">Invalid!</span>
</ng-form>
</div>
See this jsbin.
In your controller add this,
$scope.nameField = [];
in ng-reapeat add this,
<div ng-repeat="x in TestData">
<input type="text" ng-model="nameField[$index]"/>
</div>
nameField will be an array with all your values.
<div ng-repeat="x in TestData" ng-init='this["nameField-"+x]'>
<input ng-model='this["nameField-"+x]'/>
</div>
You use ng-init to add new variables to the controller, "this" refer to your scope, and since the scope is an object, since this[bla] == this.bla tou are actually saying, add to my scope a variable name "nameField=" and you add the x value.
after you have created your variable, just use it in the same way in your ng-model.
If you want to show your variable's value in any div/span, just use it via ng-bind:
<div ng-bind='this["nameField-"+x]'></div>

How to repeat duplicate objects using ng-repeat in AngularJs?

This is my code.
$scope.data=[];
$scope.data=[{"label":"name","type":"string"},{"label":"email","type":"string"}];
$scope.addFields = function (field) {
$scope.data.push(field);
};
This is my html:-
<div ng-repeat="eachItem in data">
<input type="button" value="add" ng-click="addFields(eachItem)"/>
<label>{{eachItem.label}}</label>
<input type="text" ng-model="fieldValue"/>
</div>
when i click add button push one more object into $scope.data array like
$scope.data=[{"label":"name","type":"string"},{"label":"email","type":"string"},{"label":"name","type":"string"}];
In the above i got an error
angular.min.js:102 Error: [ngRepeat:dupes] http://errors.angularjs.org/1.3.14/ngRepeat/dupes?p0=nestedField%20in%20fieā€¦%2C%22type%22%3A%22string%22%2C%22%24%24hashKey%22%3A%22object%3A355%22%7D
at Error (native)
I have duplicate objects after adding. because i want to repeat label names using ng-repeat in angularjs.First i have output like this
OutPut:-
name textbox
email textbox
After add button click Output:-
name textbox
email textbox
name textbox
use track by $index
var app = angular.module("app",[])
app.controller('ctrl',['$scope', function($scope){
$scope.data=[];
$scope.data=[{"label":"name","type":"string"},{"label":"email","type":"string"}];
$scope.addFields = function (field) {
$scope.data.push(field);
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<div class="item item-checkbox">
<div ng-repeat="eachItem in data track by $index">
<input type="button" value="add" ng-click="addFields(eachItem)"/>
<label>{{eachItem.label}}</label>
<input type="text" />
</div>
</div>
Use track by for this purpose.
<div ng-repeat="eachItem in data track by $index">
<input type="button" value="add" ng-click="addFields(eachItem)"/>
<label>{{eachItem.label}}</label>
<input type="text" ng-model="eachItem.value" />
</div>
You also able to use track by with your custom filed, like id, or whatever
Important: It's better to use track by in each ng-repeat, cause it's improve ng-repeat's performance (read more).
But avoid to use track by in ng-options and other cases when you use select as .. for ... construction (read more)
JsFiddle here
You have to ensure that items in the array have an unique key. If that is not possible you can use track by $index in the ng-repeat.
Check the details here

Getting the checked checkbox on ngrepeat angularjs

I am using ng-repeat in angularjs to display several checkboxes.
<div class="checkbox" ng-repeat="subject in priceinformation.subjects">
<label>
<input type="checkbox" ng-model="priceinformation.subscriptioninfo.subject.name"> {{subject.name}}
</label>
</div>
The problem is all the checkboxes are using the same model, hence if I check one, all are checked. I want to do it in a way that the model can resolve to different values. e.g.
ng-model="priceinformation.subscriptioninfo.subject.{{subject.name}}"
{{subject.name}} should resolve to something like English, History etc, hence a different model for each checkbox.
But ng-model="priceinformation.subscriptioninfo.subject.{{subject.name}}" is giving an error.
Note: {{subject.name}} is resolving correctly used elsewhere, and 'priceinformation.subscriptioninfo.subject' is working correctly.
Use [] instead of .
ng-model="priceinformation.subscriptioninfo[subject.name]"
Plnkr Demo
Script
$scope.priceinformation ={};
$scope.priceinformation.subjects = [{"name":"English"},{"name":"History"},{"name":"Maths"}];
$scope.priceinformation.subscriptioninfo ={};
<div ng-repeat="item in checks">
<input type="checkbox" ng-model="item.checked">{{item.name}}
</div>
See Plunkr

ngRepeat orderBy update after ngModel is updated

I have a list of text fields with a button below it. I can add text fields to that list dynamically with AngularJS.
The text field by default has an empty value. But I want to order the position of the list item as soon as I update the value of that text field. But when I do that the orderBy isn't triggered.
How can I make this happen?
Here's a quick demo: http://jsfiddle.net/fqnKt/214/
I just wanted to specifically note why the example was wrong (because I had the same issue even though I was using the orderBy directive).
DO NOT USE
track by $index
In your ng-repeat
I think that this is what you want:
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<ul>
<li ng-repeat="item in items | orderBy:'name'">
<input type="text" ng-model="item.name" /> {{item.name}}
</li>
</ul>
<input ng-model="newItem" type="text"></input>
<button ng-click="add(newItem)">Add</button>
</div>
</div>
Working Example

Reference the inputs created with ng-repeat in angular based on the number of variable options

The problem I'm facing, as outlined in the code, is that I can't seem to find out how to bind the second checkboxes (created with ng-repeat) to some model which I would then be able to use further down the code (showing/hiding yet another set of options). Also, I managed to show the additional number of inputs based on the count parameter in the $scope.availableOptions by using the $scope.getItterator function, but now I don't see how would I access the values of these checkboxes? I know I have to somehow use the option "ng-model" but am failing to do so, so any help appreciated.
My code is here, but am showing it here too:
html:
<div ng-controller='MyCtrl'>
Show additional options <input type="checkbox" ng-model="additionalOptions">
<div ng-show="additionalOptions">
<ul>
<li ng-repeat="option in availableOptions">
<label class="checkbox" for="opt_{{option.id}}">
<input type="checkbox" name="opt_{{option.id}}" id="opt_{{option.}}" />
{{option.name}}
<ul ng-show="if the upper checkbox is clicked">
<li>
<input type="text" ng-repeat="i in getItterator(option.count)" ng-model="SOME_VALUE_TO_BE_USED_BELOW"/>
Output the value based on what's entered above in the textboxes (SOME_VALUE_TO_BE_USED_BELOW)
</li>
</ul>
</label>
</li>
</ul>
</div>
</div>
and my js:
function MyCtrl($scope) {
$scope.availableOptions = [{"id":"1","name":"easy","count":"2"},{"id":"2","name":"medium","count":"3"},{"id":"3","name":"hard","count":"2"}];
$scope.getItterator=function(n){
var a = new Array();
for(var i=1; i <= n; i++)
a.push(i);
return a;
};
}
Try ng-model="option.checked":
<input type="checkbox" name="opt_{{option.id}}" id="opt_{{option.}}" ng-model="option.checked"/>
And then you can access this property further below like this:
<ul ng-show="option.checked">
DEMO
If you need to also reference the text box inputs. You create a new property (values) on the option. Like this:
{"id":"1","name":"easy","count":"2",values:[]}
Html:
<div ng-repeat="i in getItterator(option.count)">
<input type="text" ng-model="option.values[$index]"/>
{{option.values[$index]}}
</div>
DEMO
Use this:
<input type="checkbox" name="opt_{{option.id}}" id="opt_{{option.}}" ng-model="option.clicked"/>
{{option.name}}
<ul ng-show="option.clicked">
Basically, you are saying that the top checkbox should store its value in a model for each option option.clicked. And then only showing the information based on the scope item.
Updated Fiddle:
http://jsfiddle.net/CkHhJ/26/
UPDATE:
Here is another updated fiddle to answer your questions second part: http://jsfiddle.net/CkHhJ/27/
The difficulties you were having is likely because you are trying to build dynamic input models. Just bear in mind that you need to use an object for the dynamic values (not a plain string, eg: option.answers[$index].value and not just option.answers[$index]. See: AngularJS: Updating an input with a dynamic ng-model blurs on each key press

Resources