I need to add an active class to first item that slipped through ng-if="!item.hidden" loop. It works fine at first as $first directive means 0 index. But Let say the 0 to 3rd indexes is hidden therefore wont be displayed, and 4th index is the first to be displayed.
Here's my actual code
<div ng-if="!item.hidden" ng-repeat="item in ctrl.event.items">
<div class="title item" ng-class="{'active': $first }">
$first directive doesn't work when the index I am applying active class is not 0.
In place of ng-if condition you can filter the items.
after that $first return index 0 by default
<div ng-repeat="item in items| filter:{hidden:false}">
<div class="title item" ng-class="{'active': $first }">
{{item.value}}
</div>
Please check working plnkr https://plnkr.co/edit/mFVhkf55bvv8Z70F9ufk?p=preview
It was a good question, the problem as you mentioned, it cannot be done by $index as $index will even get counted if it the element is hidden.
But, angular is more and more powerful and it has many more alternatives.
Here is a solution from them,
In this answer I used filter to directly filter the values from the array so that, only the filtered objects will be displayed.
ng-repeat="x in records | filter: (x.hidden == true)"
what the above lines make is, it will not take into consideration, the values where hidden is true.
so, the $index will not start from '0'
Here is the working example:
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body ng-app="myApp">
<table ng-controller="myCtrl" border="1">
<tr ng-class="{'active': $index == 0 }" ng-repeat="x in records | filter: (x.hidden == true)">
<td>{{x.Name}}</td>
<td>{{x.Country}}</td>
</tr>
</table>
<script>
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.records = [
{
"Name" : "Alfreds Futterkiste",
"Country" : "Germany",
"hidden": true
},
{
"Name" : "Berglunds snabbköp",
"Country" : "Sweden",
"hidden": false
},
{
"Name" : "Centro comercial Moctezuma",
"Country" : "Mexico",
"hidden": false
},
{
"Name" : "Ernst Handel",
"Country" : "Austria",
"hidden": false
}
]
});
</script>
</body>
<style>
.active
{
background: green;
}
<style>
</html>
Here is a working DEMO
Related
<table>
<tr ng-repeat="customer in myData"
ng-if="$even" style="background-color: gray">
<td>{{$index+1}}</td>
<td>{{customer.name}}</td>
<td>{{customer.city}}</td>
</tr>
</table>
I got the data from a JSON file and display in view.I need a specific color for even/odd row using angularJS directive. Please help me. Advance thanks.
You could track by $index and determine if the row is odd or even, then set the style based off a ternary operator using the ngStyle style directive.
However, I would recommend using the ngClass directive which would give you better separation between markup and styles, and also make the DOM cleaner.
As an example:
<li ng-repeat="item in tc.list track by $index" ng-class="$index % 2 == 0 ? 'even' : 'odd'">{{item}}</li>
Full Snippet:
var app = angular.module("TestApp",[]);
app.controller("TestController", function() {
var vm = this;
vm.list = [];
function populateDummyItems() {
vm.list.push("One");
vm.list.push("Two");
vm.list.push("Three");
vm.list.push("Four");
}
populateDummyItems();
});
.even {
background-color: lightblue;
}
.odd {
background-color: yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="TestApp">
<h1>Darren's test application!</h1>
<ul ng-controller="TestController as tc">
<li ng-repeat="item in tc.list track by $index" ng-class="$index % 2 == 0 ? 'even' : 'odd'">{{item}}</li>
</ul>
</body>
External Plunker:
https://plnkr.co/edit/4LSB0oKYr0VgSQj0jTxP?p=preview
If you don't want to use css, you can try ng-style
<table>
<tr ng-repeat="customer in myData" ng-style="{'background-color':$even?evenColor:oddColor}">
<td>{{$index+1}}</td>
<td>{{customer.name}}</td>
<td>{{customer.city}}</td>
</tr>
</table>
js
$scope.evenColor = 'yellow'; // you can also enter the hex '#ffff00' here
$scope.oddColor = 'red';
If you don't want to use Stylesheets, you can use the angular ngStyle attribute
https://docs.angularjs.org/api/ng/directive/ngStyle
example:
HTML:
<div ng-app="OddEven">
<ul ng-controller="oddEvenController">
<li ng-repeat="item in list" ng-style="$index % 2 == 0 ? {'color':'blue'} : {color:'red'}">{{item}}</li>
</ul>
</div>
JS:
var angularApp = angular.module("OddEven",[]);
angularApp.controller("oddEvenController", function($scope) {
$scope.list = ["a", "b", "c", "d", "e", "f"];
});
If you can use Stylesheets, look at the accepted answer of
How to assign alternate class to rows in Angular JS?
What I need to do is show button in table, but when "name" is "True" the button should not show. Only when "name" is "False: the button should be in the table.
My Json
[
"name" : "False",
"date" : "22/02/2015"
},
{
"name" : "False",
"date" : "18/03/2013"
},
{
"name" : "True",
"date" : "12/06/2012"
}]
My table
<tr ng-repeat="name in names">
<td>{{name.name}}</td>
<td>{{name.date}}</td>
<td><button ng-model="post">POST</button></td>
</tr>
You could use ng-if to show and hide button
<tr ng-repeat="name in names">
<td>{{name.name}}</td>
<td>{{name.date}}</td>
<td>
<button ng-if="name.name === 'False'">POST</button>
</td>
</tr>
you can use ng-if or ng-show or ng-hide
<tr ng-repeat="name in names">
<td>{{name.name}}</td>
<td>{{name.date}}</td>
<td>
<button ng-if="!name.name">POST</button>
</td>
Go througth this link https://stackoverflow.com/a/21870119/6554634 to get better idea about ng-if, ng-show and ng-hide.
And there is mistake in your data, there is no opening brace for first object. This is silly but causes loss if we didn't notice.
[
{
"name" : "False",
"date" : "22/02/2015"
},
{
"name" : "False",
"date" : "18/03/2013"
},
{
"name" : "True",
"date" : "12/06/2012"
}
]
I prefer ng-if as it removes element from DOM if not necessary.
<tr ng-repeat="name in names">
<td>{{name.name}}</td>
<td>{{name.date}}</td>
<td><button ng-model="post" ng-if="name.name==='False'">POST</button></td>
</tr>
Your JSON is invalid
Use ng-show to show the button when name is True.
Working demo :
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function ($scope) {
$scope.names = [{
"name" : "False",
"date" : "22/02/2015"
},
{
"name" : "False",
"date" : "18/03/2013"
},
{
"name" : "True",
"date" : "12/06/2012"
}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<table>
<tr ng-repeat="name in names">
<td>{{name.name}}</td>
<td>{{name.date}}</td>
<td><button ng-model="post" ng-show="name.name == 'True'">POST</button></td>
</tr>
</table>
</div>
I am trying to display list of names and when click on the name it will show the country for that name , and when click on other name it will hide the previous one and show the clicked one only,
i used ng-show with variable declared in the controller but it just keep showing each items i click on it without hiding the others, this is my code:
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="myCtrl">
<div ng-repeat="x in records">
{{x.Name}}
<div ng-show="showDesc">{{x.Country}}</div>
</div>
</div>
<script>
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.showDesc = false;
$scope.records = [
{
"Name" : "Alfreds Futterkiste",
"Country" : "Germany"
},
{
"Name" : "Berglunds snabbköp",
"Country" : "Sweden"
},
{
"Name" : "Centro comercial Moctezuma",
"Country" : "Mexico"
},
{
"Name" : "Ernst Handel",
"Country" : "Austria"
}
]
});
</script>
</body>
</html>
ng-repeat has its own scope. So showDesc = true initializes a showDesc field in the ng-repeat scope. Each item has its own showDesc.
You want a global flag, common to all the items. And that can't just be a flag: you need to know which item must be expanded.
So just change the code to
$scope.expandedRecord = null;
$scope.expand = function(record) {
$scope.expandedRecord = record;
}
and
<div ng-repeat="x in records">
{{x.Name}}
<div ng-show="expandedRecord === x">{{x.Country}}</div>
</div>
In my html
<div ng-app="myApp" ng-controller="customersCtrl">
<table border="1">
<tr ng-repeat="x in names">
<td>{{x.Name}}</td>
<td>{{x.City}}</td>
<td>{{x.Country}}</td></tr>
</table>
</div>
<a href="#" >Show or Hide Button</a>
In my controller
var app = angular.module('myApp', []);
app.controller('customersCtrl', function($scope) {
$scope.names =[
{
"Name" : "Max Joe",
"City" : "Lulea",
"Country" : "Sweden"
},
{
"Name" : "Manish",
"City" : "Delhi",
"Country" : "India"
}
];
});
I need to show the button if there are no records or 1 of the country is India. I'm working on this but no avail http://jsfiddle.net/junedc/n8ejgtwa/1/ Thanks for the help guys really appreciated.
Use an array filter as well as array length to set a boolean
var hasIndia = $scope.names.filter(function(item){
return item.Country === 'India'
}).length;
$scope.showButton = !$scope.names.length || hasIndia;
In view:
<a ng-show="showButton" href="#" >Show or Hide Button</a>
I am defining a custom filter like so:
<div class="idea item" ng-repeat="item in items" isoatom>
<div class="section comment clearfix" ng-repeat="comment in item.comments | range:1:2">
....
</div>
</div>
As you can see the ng-repeat where the filter is being used is nested within another ng-repeat
The filter is defined like this:
myapp.filter('range', function() {
return function(input, min, max) {
min = parseInt(min); //Make string input int
max = parseInt(max);
for (var i=min; i<max; i++)
input.push(i);
return input;
};
});
I'm getting:
Error: Duplicates in a repeater are not allowed. Repeater: comment in item.comments | range:1:2 ngRepeatAction#https://ajax.googleapis.com/ajax/libs/angularjs/1.1.4/an
The solution is actually described here: http://www.anujgakhar.com/2013/06/15/duplicates-in-a-repeater-are-not-allowed-in-angularjs/
AngularJS does not allow duplicates in a ng-repeat directive. This means if you are trying to do the following, you will get an error.
// This code throws the error "Duplicates in a repeater are not allowed.
// Repeater: row in [1,1,1] key: number:1"
<div ng-repeat="row in [1,1,1]">
However, changing the above code slightly to define an index to determine uniqueness as below will get it working again.
// This will work
<div ng-repeat="row in [1,1,1] track by $index">
Official docs are here: https://docs.angularjs.org/error/ngRepeat/dupes
For those who expect JSON and still getting the same error, make sure that you parse your data:
$scope.customers = JSON.parse(data)
I was having an issue in my project where I was using ng-repeat track by $index but the products were not getting reflecting when data comes from database. My code is as below:
<div ng-repeat="product in productList.productList track by $index">
<product info="product"></product>
</div>
In the above code, product is a separate directive to display the product.But i came to know that $index causes issue when we pass data out from the scope. So the data losses and DOM can not be updated.
I found the solution by using product.id as a key in ng-repeat like below:
<div ng-repeat="product in productList.productList track by product.id">
<product info="product"></product>
</div>
But the above code again fails and throws the below error when more than one product comes with same id:
angular.js:11706 Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater
So finally i solved the problem by making dynamic unique key of ng-repeat like below:
<div ng-repeat="product in productList.productList track by (product.id + $index)">
<product info="product"></product>
</div>
This solved my problem and hope this will help you in future.
What do you intend your "range" filter to do?
Here's a working sample of what I think you're trying to do: http://jsfiddle.net/evictor/hz4Ep/
HTML:
<div ng-app="manyminds" ng-controller="MainCtrl">
<div class="idea item" ng-repeat="item in items" isoatom>
Item {{$index}}
<div class="section comment clearfix" ng-repeat="comment in item.comments | range:1:2">
Comment {{$index}}
{{comment}}
</div>
</div>
</div>
JS:
angular.module('manyminds', [], function() {}).filter('range', function() {
return function(input, min, max) {
var range = [];
min = parseInt(min); //Make string input int
max = parseInt(max);
for (var i=min; i<=max; i++)
input[i] && range.push(input[i]);
return range;
};
});
function MainCtrl($scope)
{
$scope.items = [
{
comments: [
'comment 0 in item 0',
'comment 1 in item 0'
]
},
{
comments: [
'comment 0 in item 1',
'comment 1 in item 1',
'comment 2 in item 1',
'comment 3 in item 1'
]
}
];
}
If by chance this error happens when working with SharePoint 2010: Rename your .json file extensions and be sure to update your restService path. No additional "track by $index" was required.
Luckily I was forwarded this link to this rationale:
.json becomes an important file type in SP2010. SP2010 includes certains webservice endpoints. The location of these files is 14hive\isapi folder. The extension of these files are .json. That is the reason it gives such a error.
"cares only that the contents of a json file is json - not its file extension"
Once the file extensions are changed, should be all set.
Just in case this happens to someone else, I'm documenting this here, I was getting this error because I mistakenly set the ng-model the same as the ng-repeat array:
<select ng-model="list_views">
<option ng-selected="{{view == config.list_view}}"
ng-repeat="view in list_views"
value="{{view}}">
{{view}}
</option>
</select>
Instead of:
<select ng-model="config.list_view">
<option ng-selected="{{view == config.list_view}}"
ng-repeat="view in list_views"
value="{{view}}">
{{view}}
</option>
</select>
I checked the array and didn't have any duplicates, just double check your variables.
Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys.
Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}
Example
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<script src="angular.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="personController">
<table>
<tr> <th>First Name</th> <th>Last Name</th> </tr>
<tr ng-repeat="person in people track by $index">
<td>{{person.firstName}}</td>
<td>{{person.lastName}}</td>
<td><input type="button" value="Select" ng-click="showDetails($index)" /></td>
</tr>
</table> <hr />
<table>
<tr ng-repeat="person1 in items track by $index">
<td>{{person1.firstName}}</td>
<td>{{person1.lastName}}</td>
</tr>
</table>
<span> {{sayHello()}}</span>
</div>
<script> var myApp = angular.module("myApp", []);
myApp.controller("personController", ['$scope', function ($scope)
{
$scope.people = [{ firstName: "F1", lastName: "L1" },
{ firstName: "F2", lastName: "L2" },
{ firstName: "F3", lastName: "L3" },
{ firstName: "F4", lastName: "L4" },
{ firstName: "F5", lastName: "L5" }]
$scope.items = [];
$scope.selectedPerson = $scope.people[0];
$scope.showDetails = function (ind)
{
$scope.selectedPerson = $scope.people[ind];
$scope.items.push($scope.selectedPerson);
}
$scope.sayHello = function ()
{
return $scope.items.firstName;
}
}]) </script>
</body>
</html>
If you call a ng-repeat within a < ul> tag, you may be able to allow duplicates. See this link for reference.
See Todo2.html
Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: sdetail in mydt, Duplicate key: string: , Duplicate value:
I faced this error because i had written wrong database name in my php api part......
So this error may also occurs when you are fetching the data from database base, whose name is written incorrect by you.
My JSON response was like this:
{
"items": [
{
"index": 1, "name": "Samantha", "rarity": "Scarborough","email": "maureen#sykes.mk"
},{
"index": 2, "name": "Amanda", "rarity": "Vick", "email": "jessica#livingston.mv"
}
]
}
So, I used ng-repeat = "item in variables.items" to display it.