Can I use ng-repeat to iterate over an array in AngularJS? - angularjs

I am having some trouble with using AngularJS ng-repeat. Here is what I have:
<div ng:show="selected == 3">
<div class="columns">
<textarea rows="4" data-ng-model="modal.data.answer[1].text" cols="91">1</textarea>
</div>
<div class="columns">
<label>Explanation</label>
<textarea rows="2" data-ng-model="modal.data.answer[1].explanation" cols="91"></textarea>
</div>
<div class="columns">
<div class="colx2-left">
<span class="label">Correct</span>
<input type="checkbox" data-ng-model="modal.data.answer[1].correct" class="check-box"><input type="hidden" value="false" name="Details[0].Correct">
</div>
<div class="colx2-right">
<label>Image File</label>
<input type="text" data-ng-model="modal.data.answer[1]image" class="full-width">
</div>
</div>
</div>
The modal.data.answer array will always have six elements. Can I use ng-repeat to create the HTML for these and have it repeat even the [x] numbers in the array and have it increment the number on the first line for "selected =" from 3 to 8 ?
As far as I know I can use <div ng-repeat="t in [3,4,5,6,7,8]"> </div> but how can I get the values of t into things like:
data-ng-model="modal.data.answer[1].text"

your edit is heading in the right way, you can iterate through a list of integers easily, the you just use the value of you index like that
<div ng-repeat="t in [3,4,5,6,7,8]">
....
data-ng-model="modal.data.answer[t].text"
...
I made a fiddle if you want to try http://jsfiddle.net/DotDotDot/tweyS/ (the input field is just here to change the selected value, as in your code sample, in order to display the right fields)
have fun

Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys.
<div ng-repeat="n in [42, 42, 43, 43] track by $index">
{{n}}
</div>

Related

Nested Ng-repeat with ng-if passing proper $index

I have a nested ng-repeat with ng-if, inside each ng-if I have a check-box which is containing a ng-click function. I want to pass the nested ng-repeat's $index value through the function.
Here is my code.
<div class="student" ng-repeat="student in studentDetails.childNumber track by $index" ng-init=" studentnumber = $index">
<div ng-repeat="grmnt in student.garmentNumber track by $index" ng-init="grmntidex = $index" ng-if="grmnt.gurmentType === 'shirt'">
<div ng-click="garmentOpen = !garmentOpen;" class="z-depth-1 garmentelement">Garment</div>
<div class="garmentHeader" ng-if="garmentOpen">
<div class="garmentBody">
<div class="row">
<p class="col s6 center-align">
<input type="checkbox" id="BrandMeasurement" ng-click="msrmntSelector(grmnt)" />
<label for="BrandMeasurement">Brand Measurement</label>
</p>
<p class="col s4 center-align">
<input type="checkbox" id="BodyMeasurement" ng-click="msrmntSelector(grmnt)" />
<label for="BodyMeasurement">Body Measurement</label>
<div>
</div>
</div>
</div>
</div>
</div>
</div>
But the problem is when I am selecting the last grmnt element it's passing proper garment with id but after selecting the first element its not passing 2nd or 3rd or 4th any of the garment. In every case it's passing only the first element.
Can any one please tell me where I'm making any mistake (if any)??
Don't use ng-if on the ng-repeat just use a filter in the ng-repeat.
<div ng-repeat="grmnt in student.garmentNumber | filter:{gurmentType: 'shirt'} track by $index" ng-init="grmntidex = $index">
Edit: I think maybe the problem is in your labels. The label's for attribute needs to uniquely match the input's id attribute. Each row needs its own id/for pair. Use $index to do this.
<input type="checkbox" id="BrandMeasurement{{$index}}" ng-click="msrmntSelector(grmnt)" />
<label for="BrandMeasurement{{$index}}">Brand Measurement</label>

$index in ng-class for form validation

I want to validate an angular form input and give it a class if is not $valid, the problem is, it´s inside a ng-repeat looping an array of int, and the input name is based on the $index:
<li ng-repeat="item in selectedItem.data.ax_ch">
<div ng-class="{'has-error':!form.ax_$index.$valid}">
<input type="text" id="ax_{{$index}}" name="ax_{{$index}}" ng-model="item" required=""/>
</div>
</li>
Everything gets the $index in the output, but the ng-class:
<li ng-repeat="item in selectedItem.data.ax_ch">
<div ng-class="{'has-error':!form.ax_$index.$valid}">
<input type="text" id="ax_0" name="ax_0" ng-model="item" required=""/>
</div>
</li>
What I expected it to be:
<li ng-repeat="item in selectedItem.data.ax_ch">
<div ng-class="{'has-error':!form.ax_0.$valid}">
<input type="text" id="ax_0" name="ax_0" ng-model="item" required=""/>
</div>
</li>
I have searched and people have similar problems but none of them have been solved so far. Is there any angular-super-hero-master-plus-advanced who can help me with it :) ?
Because you are constructing the property/key on form dynamically, you do the same thing you would in normal Javascript: use square["bracket"] notation.
Change your markup to:
<li ng-repeat="item in selectedItem.data.ax_ch">
<div ng-class="{'has-error':!form['ax_' + $index].$valid}">
<input type="text" id="ax_{{$index}}" name="ax_{{$index}}" ng-model="item" required=""/>
</div>
</li>

Angular ng-repeat. Looping through the letters in string

I'va just started learning Angular and can't manage an issue with ng-repeat.
I want to display every letter from input in a single span element. I tried many ways but nothing works.
Here's my code on codepen
Is this what you're looking for ?
Each letter will be printed in different span.
solution of Error: ngRepeat:dupes
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
});
.center-block {
float: none;
}
input {
margin: 20px;
}
span:hover {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl" class="container">
<div class="col-sm-10 center-block text-center">
<input type="text" class="form-control" placeholder="Type to search..." ng-model="word" />
<div ng-repeat="letter in word.split('') track by $index">
<span> {{ letter }} </span>
</div>
<br/><br/> If you want to split the word by line <br/><br/>
<div ng-repeat="letter in word.split(' ') track by $index">
<span> {{ letter }} </span>
</div>
</div>
</div>
You need to reference the alias Letter as opposed to Word
<div ng-app="myApp" ng-controller="myCtrl" class="container">
<div class="col-sm-10 center-block text-center">
<input type="text" class="form-control" placeholder="Type to search..." ng-model="word" />
<div ng-repeat="letter in word.split('') track by $index">
<span> {{letter }} </span>
</div>
</div>
</div>
EDIT
Apparently what is happening is word.split('') is not allowing any duplicates.
"thisisatest".split('') if this is input into the console, it splits you expect it to. I dont understand why word.split('') is removing duplicates. Type a string with unique chars into your codepen and it will display correctly.
EDIT
per p2. answer the track by $index tracks all duplicates. which fixes the issue. The split is resulting in duplicate items in an array and without track by $index angular is just not displaying the duplicates
You should also be using track by $index with ng-repeat to deal with Duplicate Key in Repeater
<div ng-app="myApp" ng-controller="myCtrl" class="container">
<div class="col-sm-10 center-block text-center">
<input type="text" class="form-control" placeholder="Type to search..." ng-model="word" />
<div ng-repeat="letter in word.split('') track by $index">
<span> {{letter }} </span>
</div>
</div>
</div>

Get ng-repeat data to appear in 4 columns

I'm getting list of data from Db to a view using ng-repeat. In order to select multiple values at once I'm using checklist-model. My code is as follows,
<div ng-repeat="item in items">
<input type=checkbox checklist-model="user.role" checklist-value="item"/>{{item}}
</div>
This will return a long list one below another. What I need is to get these data in the list to be displayed in 4 columns. Any help please!
Working Demo
This is what you are looking for. Hope that solve your problem.
<div ng-repeat="product in products" ng-if="$index % 3 == 0" class="row">
<div class="col-xs-4"> <input type="checkbox" checklist-model="user.role" checklist-value="{{products[$index]}}"/>{{products[$index]}}</div>
<div class="col-xs-4"> <input type="checkbox" checklist-model="user.role" checklist-value="{{products[$index]}}"/>{{products[$index+1]}}</div>
<div class="col-xs-4"> <input type="checkbox" checklist-model="user.role" checklist-value="{{products[$index]}}"/>{{products[$index+2]}}</div>
</div>
Output:
You could use display:inline-block on your elements that you want in a row. How you lay them out within that row could be done different ways depending on what you are seeking.
<div ng-repeat="item in items" style="display:inline-block;">
<input type=checkbox checklist-model="user.role" checklist-value="item"/>{{item}}
</div>

ng-repeat execution forces input to lose focus

I have an input that is created using ng-repeat
<div data-ng-repeat="(index, answer) in currentQuestion['possible_answers']" class="form-group">
<label class="col-md-3 control-label">Answer {{ index + 1 }}</label>
<div class="col-md-8">
<div class="input-icon">
<i class="fa fa-sun-o"></i>
<input data-ng-model="currentQuestion['possible_answers'][index]" type="text" class="form-control" >
</div>
</div>
</div>
I want this to prepopulate the inputs with the values that are in currentQuestion['possible_answers'] and I also want any changes to bind to this variable as well.
However, everytime I start typing into one of these text fields, I type one letter and then it looses focus of the input box. I have a feeling that this is because I start typing and the data bidning updates currentQuestion. Because currentQuestion is updated, the ng-repeat is executed again.
Is there a way to make the ng-repeat action a one off action isntead of constantly revalutating?
Yes (looking at the symptoms, you did not show us the data) your issue could be because your model is the text in the array that you (may have), so whenever you update the model, it will trigger digest cycle since ng-repeat is tracked by the text. You can easily fix this by providing. track by $index, so that the ng-repeat is watched over and repeat watch gets updated only when the array changes in its length.
<div data-ng-repeat="answer in currentQuestion['possible_answers'] track by $index" class="form-group">
<label class="col-md-3 control-label">Answer {{ $index + 1 }}</label>
<div class="col-md-8">
<div class="input-icon">
<i class="fa fa-sun-o"></i>
<input data-ng-model="currentQuestion['possible_answers'][$index]" type="text" class="form-control" >
</div>
</div>
</div>
Demo
You can also use $index to get the array's index. you do not need to iterate with (key, value).
However i would just make my answer array an array of objects and get rid of all these issues, and it would just be (_note the usage of $index and ng-model):-
<div data-ng-repeat="answer in currentQuestion['possible_answers'] track by $index" class="form-group">
<label class="col-md-3 control-label">Answer {{ $index + 1 }}</label>
<div class="col-md-8">
<div class="input-icon">
<i class="fa fa-sun-o"></i>
<input data-ng-model="answer.text" type="text" class="form-control" >
</div>
</div>
</div>
Demo
The ng-repeat creates a new child scope for each item in the list. In this scope it knows index and answer. You bind the value of the input to something outside the scope, namely the same item in the array. Changing it triggers the list to be redrawn, which causes the input to loose focus.
<div data-ng-repeat="(index, answer) in currentQuestion['possible_answers']" class="form-group">
<label class="col-md-3 control-label">Answer {{ index + 1 }}</label>
<div class="col-md-8">
<div class="input-icon">
<i class="fa fa-sun-o"></i>
<input data-ng-model="answer" type="text" class="form-control" >
</div>
</div>
</div>

Resources