AngularJS add incremental value - angularjs

Is it possible to add an incremental identifier to ng-model in AngularJS?
I'm iterating a list of items, and need to and an incremental value to the ng-model="" attribute for each item in the loop, or if there is a simpler way, I'd like to hear it.
What I'm currently trying:
<li ng-repeat="recipe in recipes">
<label for="cost_ingredient_{{recipe.ingredient_id}}" style="font-size: 16px;">{{recipe.ingredient}}</label>
<input ng-model="{{recipe.model_name}}" name="formcost_ingredient_{{recipe.ingredient_id}}" type="number" id="cost_ingredient_{{recipe.ingredient_id}}" min="0" step="0.01" value="0" />
</li>
I tried doing this with a directive, but when I call 'formData' in the controller, none of the model indices come up.
I need to pass this information, as part of a form submission back to the next page in the process. This will be deployed to Android, so I'm thinking of just adding this to window.sessionStorage as I only need this once for every time a user runs my app.

Try using $index property to generate unique ID:
<div ng-repeat="item in items">
<span id="unique_ID_{{ $index }}">{{ item }}</span>
</div>
http://plnkr.co/edit/SPeyIb2dGxPpL3yKykr6?p=preview

On iteration, attach an id in the repeater with ng-init. This will modify your original structure and the id will be available outside the repeater.
<li ng-repeat="recipe in recipes" >
<label ng-init="recipe.someId = $index" for="cost_ingredient_{{recipe.someId}}" >
{{recipe.ingredient}}
</label>
<input ng-model="{{recipe.model_name}}" name="formcost_ingredient_{{recipe.someId}}"
type="number" id="cost_ingredient_{{recipe.someId}}"
min="0" step="0.01" value="0" />
</li>
This is similar to Michal Stefanow's answer, except here you actually change the structure by adding an attribute to each item, in this case it's called someId
Another way:
<li ng-repeat="recipe in recipes" >
<label ng-init="recipe.costIngredient = 'cost_ingredient_' + $index" for="{{recipe.costIngredient}}" >
{{recipe.ingredient}}
</label>
<input ng-model="{{recipe.model_name}}"
ng-init="recipe.formcostIngredient = 'formcost_ingredient_' + $index" name="{{recipe.formcostIngredient}}"
type="number" id="{{recipe.costIngredient}}"
min="0" step="0.01" value="0" />
</li>
What you'd really want is to pre-process this on the JavaScript side so that it's not evaluated every time:
$scope.recipes = [ your array here ];
angular.forEach($scope.recipes, function(recipe, index){
recipe.costIngredient = 'cost_ingredient_' + index;
recipe.formcostIngredient = 'formcost_ingredient_' + $index;
});
then iterate over that.
P.S. you may want to look into using ng-bind rather than {{ }} to generate the HTML, it's better for unforeseen errors

Related

How to access from parent form to a certain child form generated in ng-repeat without the need to add things like frmChild {{$index}}?

How to access from frmParent to a certain frmChild? (without the need to add things like: frmChild {{$index}}).
<div ng-form="frmParent">
How to know frmChild (i.e at index 3) $pristine value from HERE
<div ng-form="frmChild" ng-repeat="item in mct.listOfElements">
{{item.Name}}:
<input type="text" ng-model="item.Value" /> Pristine: {{frmChild.$pristine}}
</div>
</div>
Here is a working example to play with what i'm talking about.
You can use unique names for your child forms, ex. item.Name if it's supposed to be unique:
<div ng-repeat="item in mct.listOfElements" ng-form="{{item.Name}}">
{{item.Name}}:
<input type="text" ng-model="item.Value" /> Pristine: {{frmParent[item.Name].$pristine}}
</div>
And then refer to any required child form by it's name:
D now is pristine: {{frmParent.D.$pristine}}
Please see the Plunker.

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

ng-models name collision inside ng-repeat

http://plnkr.co/edit/2UFfaG?p=preview
I used this sample code to build a simple app and I noticed that the edit function doesn't work when you are using ng-models that are repeated in a loop. I know this, because I tried using ng-models outside of the ng-repeat loop and it worked perfectly. So when you have two instances of ng-models with the same name, you get a blank data back when you try to get the values back from the view.
This is my view:
<ul ng-repeat="notes in notes">
<li>
<span ng-hide="editing" ng-click="editing = true">{{note.name}} | {{note.content}}</span>
<form ng-show="editing" ng-submit="editing = false">
<label>Name:</label>
<input type="text" ng-model="name" placeholder="Name" ng-required/>
<label>Content:</label>
<input type="date" ng-model="content" placeholder="Content" ng-required/>
<br/>
<button class="btn" ng-click="edit(note.id)">Save</button>
</form>
</li>
</ul>
This is my edit method:
$scope.edit = function (id) {
var note = notesRef.child(id);
var newNote= {
name : $scope.name,
content : $scope.content
}
};
note.update(newNote);
};
When I refer to a ng-model inside of ng-repeat, I can only get the value null for some reason. I get the correct value when I refer to ng-models outside of the ng-repeat for some reason.
How do we solve this problem? What's the simplest solution?
The problem is that the item belongs to the scope of the repeat.
If you changed your ng-model to:
<ul ng-repeat="notes in notes">
<li>
<span ng-hide="editing" ng-click="editing = true">{{note.name}} | {{note.content}}</span>
<form ng-show="editing" ng-submit="editing = false">
<label>Name:</label>
<input type="text" ng-model="note.name" placeholder="Name" ng-required/>
<label>Content:</label>
<input type="date" ng-model="note.content" placeholder="Content" ng-required/>
<br/>
<button class="btn" ng-click="edit(note)">Save</button>
</form>
</li>
</ul>
Where it's now note.name / note.content.
Then instead of padding the note.id to the edit button, you pass in the entire note i.e ng-click="edit(note)"
Then your controller will get passed the entire note.
$scope.edit = function (note) {
// send note to server via $http, changes to `note` are already made directly to the note itself
};
Hope that makes sense.
it should be like this. As we know ng-repeats directive create their own new scope.
bday.editing
<ul ng-repeat="bday in bdays">
<li>
<span ng-hide="bday.editing" ng-click="bday.editing = true">{{bday.name}} | {{bday.date}}</span>
<form ng-show="bday.editing" ng-submit="bday.editing = false">
<label>Name:</label>
<input type="text" **ng-model="bday.name"** placeholder="Name" ng-required/>
<label>Date:</label>
<input type="date" **ng-model="bday.date"** placeholder="Date" ng-required/>
<br/>
<button class="btn" type="submit">Save</button>
</form>
</li>
</ul>
and here what I understand from your question is that you want to edit only the item on which you have click. this is the solution for the same.
One more solution for the same problem is that create a new function that take one argument that is "bday". make edit true only for this item and set editing false for all others element. this solution is for that case if user doesn't submit the form and click on other item.

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

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

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>

Resources