$index of ng-repeat not incremented inside ng-if - javascript

$index value not increment inside ng-if block.
<div ng-repeat="household in census.households track by $index">
<div ng-if="household.ask_for_tobacco">
<input id="tobacco_{{$index}}" type="checkbox" ng-model="member.smoker">
<label for="tobacco_{{$index}}"></label>
</div>
</div>
In above block, I am using ng-repeat and ng-if inside it. I am following condition ng-if and setting element id with $index. Element ID is being set 0 every time, rather than incremented to 1,2,3...
If ng-if removed, it works without fail. So anyone has used and faced same issue. Please give me solution.

Your problem is that ng-if creates its own scope which then interferes with your access to the scope of the iteration that is created by ng-repeat.
Because you can't use ng-show, my suggestion is that you apply a filter to your ng-repeat like this:
<div ng-app="app" ng-controller="MyCtrl">
<div ng-repeat="household in households | filter: { ask_for_tobacco: true }">
<input id="tobacco_{{$index}}" type="checkbox">
<label for="tobacco_{{$index}}">index {{ $index }} id = {{ household.id }}</label>
</div>
</div>
See working example here: http://jsfiddle.net/m25afg12/9/

you can use $parent.$index
late though for ans :D

Related

How to use the ng-repeat $index variable in an AngularJs expression?

I'm generating a lot of HTML with ng-repeat. I rely on the $index variable in order to index data in my controller.
I do alot of stuff like
ng-submit="validateExistingGuest($index)"
In this case, an undetermined number of HTML forms is generated, hence the index.
Problem is, i sometimes need to use this variable inside a different kind of expression. That would look something like that:
ng-if= "user{{$index}}.valid"
Of course, that doesn't work. I tried ways of constructing that expression, with no success.
How would one go about doing this?
You need something like
ng-if="user[$index].valid
<div ng-repeat="value in user track by $index"> ...
//now you can use the {{$index}}
<div ng-if="user[$index].valid">Show only if valid!</div>
</div>
Why don't you use the object instead the $index?, try
<div ng-repeat="car in cars" >
<p {{car}}></p>
<button ng-click="buy(car)" > buy </button>
</div>

AngularJS ngMessages can't bind to $index expression

I am building an Angular form that needs repeatable form elements inside an ngRepeat.
<form name="form">
<div ng-repeat="x in [1,2,3,4]">
<input name="something_{{$index}}" ng-model="hi" required>
<div ng-messages="form.something_{{$index}}.$error">
<ng-message="required">This is required</ng-message>
</div>
</div>
<pre>{{form | json: 4}}</pre>
</form>
Angular now supports dynamically declared input names so that you don't have to do something like:
<div ng-repeat="x in [1,2,3,4] ng-form="repeated-form"></div>
And you can use {{$index}} inside the ngRepeat to declare items dynamically. But this doesn't seem to work with ngMessages, which throws an error when I try to bind the index into it.
i.e. this:
<div ng-messages="form.something_{{$index}}.$error">
throws this:
Error: [$parse:syntax] Syntax Error: Token '{' is an unexpected token at column 16 of the expression [form.something_{{$index}}.$error] starting at [{{$index}}.$error].
How can we dynamically declare which property on the form to watch, if ng-messages can't watch the form value that is declared with its {{$index}}?
PLNKR: http://plnkr.co/edit/4oOasbtffTgKqmxcppUG?p=preview (check console)
ng-messages="form['something_' + $index].$error"
Should work. I generally wouldn't put {{ }} in any of the ng directives because most of the ng directives execute with priority level 0 (including the {{ }} directive, ngBind). Also, the ng directives all use $evaluate on their argument, so they look at variable values in the scope by default.
Priority 0 for multiple directives on the same element means that Angular can't guarantee which directive will be applied first. Because of that, it is generally best to avoid using ngDirectives together as behavior can vary. ngIf is an exception as it executes with priority 600 (which is why directives aren't evaluated for an ng-if element not currently in the DOM no matter what).
<div ng-repeat="x in [0,1,2,3]">
<input name="something_{{$index}}" ng-model="hi" required>
<div ng-messages="form['something_' + $index].$error">
<ng-message="required">This is required</ng-message>
</div>
</div>
http://plnkr.co/edit/k5nzkpkJwSuf5dvlMMZi?p=preview

Angular ng-repeat with bootstrap input checkbox with dynamic ng-model using ng-true-value

This problem is a little tricky for me to explain so I'll do my best. I'm trying to successfully implement Angular checkbox with their ng-true-value correctly with a dynamic ng-model.
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<div ng-repeat="asset in asset">
<h5>{{ asset.title }} categories are...{{ asset.category[0] + " and " + asset.category[1] }}</h5>
<div class="form-group">
<label>Business</label>
<div class="checkbox" ng-repeat="category in categoryFactory.business">
<input type="checkbox" id="{{category}}" ng-true-value="{{'category'}}" ng-model="asset.category[$index]">
<label for="{{category}}">{{category}}</label>
</div>
</div>
<div class="form-group">
<label>Personal</label>
<div class="checkbox" ng-repeat="category in categoryFactory.personal">
<input type="checkbox" id="{{category}}" ng-true-value="{{'category'}}" ng-model="asset.category[$index]">
<label for="{{category}}">{{category}}</label>
</div>
</div>
</div>
</div>
My end goal is when I load up my asset (find below...) it will display like the picture here My end goal, with the correct checkboxes checked. The Business and Personal categories are derived from a factory and each form-group checkbox's are from an ng-repeat list in Business / Personal in the factory.
$scope.asset = [{
title: "Sales Agreement",
category: ["finance-admin", "running-a-business"]
}];
My issue is having to correctly implement ng-model inside the checkbox. Since each asset can have 1 or more category it needs to be dynamic. I have tried using $index to make my ng-model dynamic...
ng-model="asset.category[$index]"
But that seems to not work like I would have hoped. I am probably missing something very easy and some help would be greatly appreciated.
Thanks!
By the way here is the
JSFIDDLE
Currently as per your $index logic the two arrays categoryFactory.business and asset.category must be of same size so here is the updated jsfiddle
but the main part is this
First, for your case ng-true-value should be an expression
ng-true-value="{{category}}"
Second, your asset.category array indices should match with your options in categoryFactory.business array
$scope.asset = [{
title: "Sales Agreement",
category: ["", "running-a-business","", "","finance-admin"]
}];
There could be a better option to manage this without relying on the $index but this should do for your case
I used ng-checked, you can put function as an attribute value, ng-repeat will evaluate the function in each loop.
<input type="checkbox" id="{{category}}" ng-checked="isCategory(category)" >
$scope.isCategory = function(category){
return $scope.asset[0].category.indexOf(category) >= 0;
}
In isCategory() we are checking the indices of the category in asset.category array, if it finds it will true.
https://jsfiddle.net/pg5dqgr9/8/

AngularJS: ng-if outside ng-repeat breaks ng-repeat

AngularJS Verion: 1.3.8
JSFiddle: http://jsfiddle.net/uYFE9/4/
I've been working on a small AngularJS application, and ran into a bit of a problem. I have an ng-repeat on a page, which fills in the contents of a form. The amount of items in the form is defined by a dropdown bound to a model, and populated using ng-options. Something like:
<select id="testAmount" ng-model="selectedItem" ng-options="item.name for item in items"></select>
<form role="form" name="testForm" ng-if="!complete">
<div ng-repeat="i in getNumber(selectedItem.number) track by $index">
{{$index}}
</div>
</form>
Complete is set to false in the beginning, and hitting a Next button will toggle complete and hide the form and dropdown. A Back button will then toggle complete back, and show the form again.
The problem I'm having is with the ng-if on the select (and previously, I had the form wrapped in a div with the same ng-if - same problem). The ng-repeat no longer updates when the select dropdown is changed. Removing the ng-if on the select restores the ng-repeat to working order.
I'm wondering if there's something strange I'm doing with the nesting here, or if it's actually a bug? You can test it out on the JSFiddle linked above. The $index should be printed the number of times on the dropdown, but isn't.
Interestingly enough - when debugging the problem on my local machine, having FireBug open fixed the issue.
This is because of ng-if creating a child scope and how prototypical inheritance works with primitives. In this case, the primitive is selectedItem that you are setting by the <select>, but is actually being set on the child scope and shadows/hides the parent scope property.
In general you should always use a dot (.) with ng-models:
$scope.selection = {selectedItem: undefined};
And in the View:
<div ng-if="!complete">
<select ng-model="selection.selectedItem"
ng-options="item.name for item in items"></select>
</div>
ng-if is causing you some scoping issues (which messes with the binding).
Here is an updated jsfiddle that you could use as a work around. Essentially, this example wraps another div around the items that you want to end up hiding. And then adds a next function so that the same scope is affected during the click that sets complete to true.
HTML:
<div ng-app="test">
<div ng-controller="TestCtrl">
<div ng-if="!complete">
<div>
<label for="testAmount">Amount:</label>
<select id="testAmount" ng-model="selectedItem" ng-options="item.name for item in items"></select>
</div>
<form role="form" name="testForm">
<div ng-repeat="i in getNumber(selectedItem.number) track by $index">
{{$index + 'hi'}}
</div>
<button class="btn btn-default" value="Next" title="Next" ng-click="next()">Next</button>
</form>
</div>
<div ng-if="complete">
</div>
</div>
</div>
JS:
angular.module('test', [])
.controller('TestCtrl', function($scope) {
$scope.complete = false;
$scope.items = [
{ name: '2', number: 2 },
{ name: '3', number: 3 },
{ name: '4', number: 4 }
];
$scope.selectedItem = $scope.items[0];
$scope.getNumber = function (number) {
return new Array(number);
};
$scope.next = function() {
$scope.complete = true;
};
})
I believe the problem is with your select statement inside an ng-if the selectedItem is never getting set. If you just don't want to show that dropdown when !complete change it to an ng-show and it works fine.
<div ng-show="!complete">
As to WHY the ng-model is not being bound inside the ng-if, I don't really know but it does make some sense in that you are trying to do a conditional bind which is a bit screwy

How to insert new line within ng-repeat of the middle (Angularjs + twitter bootstrap + jade)

I want to insert new line like a following.
div.row
div.span12
div(ng-repeat="(data in datas)")
p data.text
// insert new line when $index is the number divisible by 3.
how does it do?
thank you.
You can use the ng-if directive, you would show a line break every time your $index matches a certain condition. So if you'd like to break after 3 iterations:
<div ng-repeat="data in datas">
{{ data }}
<br ng-if="($index+1)%3==0">
<div>
I am not sure what your end result will be, but there are a few ways that I would approach this. The first is to use ng-hide and ng-show to do something different on items that are divisible by 3. The other way would be to use ng-class to just style the 3rd element differently.
<div ng-repeat="data in datas">
<div ng-class="{'red': ($index+1)%3==0}">{{data}}</div>
<div>
Here is a jsFiddle

Categories