AngularJS sorting rows by table header - angularjs

I have four table headers:
$scope.headers = ["Header1", "Header2", "Header3", "Header4"];
And I want to be able to sort my table by clicking on the header.
So if my table looks like this
H1 | H2 | H3 | H4
A H D etc....
B G C
C F B
D E A
and I click on
H2
my table now looks like this:
H1 | H2 | H3 | H4
D E A etc....
C F B
B G C
A H D
That is, the content of each column never changes, but by clicking on the header I want to order the columns by, the rows will reorder themselves.
The content of my table is created by a database call done with Mojolicious and is returned to the browser with
$scope.results = angular.fromJson(data); // This works for me so far
The rest of the code I have cobbled together looks something like this:
<table class= "table table-striped table-hover">
<th ng-repeat= "header in headers">
<a> {{headers[$index]}} </a>
</th>
<tr ng-repeat "result in results">
<td> {{results.h1}} </td>
<td> {{results.h2}} </td>
<td> {{results.h3}} </td>
<td> {{results.h4}} </td>
</tr>
</table>
How do I order the columns from this point, just by clicking on the header at the top of the table?

I think this working CodePen example that I created will show you exactly how to do what you want.
The template:
<section ng-app="app" ng-controller="MainCtrl">
<span class="label">Ordered By: {{orderByField}}, Reverse Sort: {{reverseSort}}</span><br><br>
<table class="table table-bordered">
<thead>
<tr>
<th>
<a href="#" ng-click="orderByField='firstName'; reverseSort = !reverseSort">
First Name <span ng-show="orderByField == 'firstName'"><span ng-show="!reverseSort">^</span><span ng-show="reverseSort">v</span></span>
</a>
</th>
<th>
<a href="#" ng-click="orderByField='lastName'; reverseSort = !reverseSort">
Last Name <span ng-show="orderByField == 'lastName'"><span ng-show="!reverseSort">^</span><span ng-show="reverseSort">v</span></span>
</a>
</th>
<th>
<a href="#" ng-click="orderByField='age'; reverseSort = !reverseSort">
Age <span ng-show="orderByField == 'age'"><span ng-show="!reverseSort">^</span><span ng-show="reverseSort">v</span></span>
</a>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="emp in data.employees|orderBy:orderByField:reverseSort">
<td>{{emp.firstName}}</td>
<td>{{emp.lastName}}</td>
<td>{{emp.age}}</td>
</tr>
</tbody>
</table>
</section>
The JavaScript code:
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
$scope.orderByField = 'firstName';
$scope.reverseSort = false;
$scope.data = {
employees: [{
firstName: 'John',
lastName: 'Doe',
age: 30
},{
firstName: 'Frank',
lastName: 'Burns',
age: 54
},{
firstName: 'Sue',
lastName: 'Banter',
age: 21
}]
};
});

Here is a fiddle that can help you to do this with AngularJS
http://jsfiddle.net/patxy/D2FsZ/
<th ng:repeat="(i,th) in head" ng:class="selectedCls(i)" ng:click="changeSorting(i)">
{{th}}
</th>
Then something like this for your data:
<tr ng:repeat="row in body.$orderBy(sort.column, sort.descending)">
<td>{{row.a}}</td>
<td>{{row.b}}</td>
<td>{{row.c}}</td>
</tr>
With such functions in your AngularJS controller:
scope.sort = {
column: 'b',
descending: false
};
scope.selectedCls = function(column) {
return column == scope.sort.column && 'sort-' + scope.sort.descending;
};
scope.changeSorting = function(column) {
var sort = scope.sort;
if (sort.column == column) {
sort.descending = !sort.descending;
} else {
sort.column = column;
sort.descending = false;
}
};

Another way to do this in AngularJS is to use a Grid.
The advantage with grids is that the row sorting behavior you are looking for is included by default.
The functionality is well encapsulated. You don't need to add ng-click attributes, or use scope variables to maintain state:
<body ng-controller="MyCtrl">
<div class="gridStyle" ng-grid="gridOptions"></div>
</body>
You just add the grid options to your controller:
$scope.gridOptions = {
data: 'myData.employees',
columnDefs: [{
field: 'firstName',
displayName: 'First Name'
}, {
field: 'lastName',
displayName: 'Last Name'
}, {
field: 'age',
displayName: 'Age'
}]
};
Full working snippet attached:
var app = angular.module('myApp', ['ngGrid', 'ngAnimate']);
app.controller('MyCtrl', function($scope) {
$scope.myData = {
employees: [{
firstName: 'John',
lastName: 'Doe',
age: 30
}, {
firstName: 'Frank',
lastName: 'Burns',
age: 54
}, {
firstName: 'Sue',
lastName: 'Banter',
age: 21
}]
};
$scope.gridOptions = {
data: 'myData.employees',
columnDefs: [{
field: 'firstName',
displayName: 'First Name'
}, {
field: 'lastName',
displayName: 'Last Name'
}, {
field: 'age',
displayName: 'Age'
}]
};
});
/*style.css*/
.gridStyle {
border: 1px solid rgb(212,212,212);
width: 400px;
height: 200px
}
<!DOCTYPE html>
<html ng-app="myApp">
<head lang="en">
<meta charset="utf-8">
<title>Custom Plunker</title>
<link rel="stylesheet" type="text/css" href="http://angular-ui.github.com/ng-grid/css/ng-grid.css" />
<link rel="stylesheet" type="text/css" href="style.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular-animate.js"></script>
<script type="text/javascript" src="http://angular-ui.github.com/ng-grid/lib/ng-grid.debug.js"></script>
<script type="text/javascript" src="main.js"></script>
</head>
<body ng-controller="MyCtrl">
<div class="gridStyle" ng-grid="gridOptions"></div>
</body>
</html>

Here is an example that sorts by the header. This table is dynamic and changes with the JSON size.
I was able to build a dynamic table off of some other people's examples and documentation. http://jsfiddle.net/lastlink/v7pszemn/1/
<tr>
<th class="{{header}}" ng-repeat="(header, value) in items[0]" ng-click="changeSorting(header)">
{{header}}
<i ng-class="selectedCls2(header)"></i>
</tr>
<tbody>
<tr ng-repeat="row in pagedItems[currentPage] | orderBy:sort.sortingOrder:sort.reverse">
<td ng-repeat="cell in row">
{{cell}}
</td>
</tr>
Although the columns are out of order, on my .NET project they are in order.

You can use this code without arrows.....i.e by clicking on header it automatically shows ascending and descending order of elements
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="scripts/angular.min.js"></script>
<script src="Scripts/Script.js"></script>
<style>
table {
border-collapse: collapse;
font-family: Arial;
}
td {
border: 1px solid black;
padding: 5px;
}
th {
border: 1px solid black;
padding: 5px;
text-align: left;
}
</style>
</head>
<body ng-app="myModule">
<div ng-controller="myController">
<br /><br />
<table>
<thead>
<tr>
<th>
<a href="#" ng-click="orderByField='name'; reverseSort = !reverseSort">
Name
</a>
</th>
<th>
<a href="#" ng-click="orderByField='dateOfBirth'; reverseSort = !reverseSort">
Date Of Birth
</a>
</th>
<th>
<a href="#" ng-click="orderByField='gender'; reverseSort = !reverseSort">
Gender
</a>
</th>
<th>
<a href="#" ng-click="orderByField='salary'; reverseSort = !reverseSort">
Salary
</a>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="employee in employees | orderBy:orderByField:reverseSort">
<td>
{{ employee.name }}
</td>
<td>
{{ employee.dateOfBirth | date:"dd/MM/yyyy" }}
</td>
<td>
{{ employee.gender }}
</td>
<td>
{{ employee.salary }}
</td>
</tr>
</tbody>
</table>
</div>
<script>
var app = angular
.module("myModule", [])
.controller("myController", function ($scope) {
var employees = [
{
name: "Ben", dateOfBirth: new Date("November 23, 1980"),
gender: "Male", salary: 55000
},
{
name: "Sara", dateOfBirth: new Date("May 05, 1970"),
gender: "Female", salary: 68000
},
{
name: "Mark", dateOfBirth: new Date("August 15, 1974"),
gender: "Male", salary: 57000
},
{
name: "Pam", dateOfBirth: new Date("October 27, 1979"),
gender: "Female", salary: 53000
},
{
name: "Todd", dateOfBirth: new Date("December 30, 1983"),
gender: "Male", salary: 60000
}
];
$scope.employees = employees;
$scope.orderByField = 'name';
$scope.reverseSort = false;
});
</script>
</body>
</html>

Use a third-party JavaScript library. It will give you that and much more. A good example is datatables (if you are also using jQuery): https://datatables.net
Or just order your bound array in $scope.results when the header is clicked.

I'm just getting my feet wet with angular, but I found this great tutorial.
Here's a working plunk I put together with credit to Scott Allen and the above tutorial. Click search to display the sortable table.
For each column header you need to make it clickable - ng-click on a link will work. This will set the sortName of the column to sort.
<th>
<a href="#" ng-click="sortName='name'; sortReverse = !sortReverse">
<span ng-show="sortName == 'name' && sortReverse" class="glyphicon glyphicon-triangle-bottom"></span>
<span ng-show="sortName == 'name' && !sortReverse" class="glyphicon glyphicon-triangle-top"></span>
Name
</a>
</th>
Then, in the table body you can pipe in that sortName in the orderBy filter orderBy:sortName:sortReverse
<tr ng-repeat="repo in repos | orderBy:sortName:sortReverse | filter:searchRepos">
<td>{{repo.name}}</td>
<td class="tag tag-primary">{{repo.stargazers_count | number}}</td>
<td>{{repo.language}}</td>
</tr>

I had found the easiest way to solve this question. If efficient you can use
HTML code: import angular.min.js and the angular.route.js library
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>like/dislike</title>
</head>
<body ng-app="myapp" ng-controller="likedislikecntrl" bgcolor="#9acd32">
<script src="./modules/angular.min.js"></script>
<script src="./modules/angular-route.js"></script>
<script src="./likedislikecntrl.js"></script>
</select></h1></p>
<table border="5" align="center">
<thead>
<th>professorname <select ng-model="sort1" style="background-color:
chartreuse">
<option value="+name" >asc</option>
<option value="-name" >desc</option>
</select></th>
<th >Subject <select ng-model="sort1">
<option value="+subject" >asc</option>
<option value="-subject" >desc</option></select></th>
<th >Gender <select ng-model="sort1">
<option value="+gender">asc</option>
<option value="-gender">desc</option></select></th>
<th >Likes <select ng-model="sort1">
<option value="+likes" >asc</option>
<option value="-likes" >desc</option></select></th>
<th >Dislikes <select ng-model="sort1">
<option value="+dislikes" >asc</option>
<option value="-dislikes">desc</option></select></th>
<th rowspan="2">Like/Dislike</th>
</thead>
<tbody>
<tr ng-repeat="sir in sirs | orderBy:sort1|orderBy:sort|limitTo:row" >
<td >{{sir.name}}</td>
<td>{{sir.subject|uppercase}}</td>
<td>{{sir.gender|lowercase}}</td>
<td>{{sir.likes}}</td>
<td>{{sir.dislikes}}</td>
<td><button ng-click="ldfi1(sir)" style="background-color:chartreuse"
>Like</button></td>
<td><button ng-click="ldfd1(sir)" style="background-
color:chartreuse">Dislike</button></td>
</tr>
</tbody>
</table>
</body>
</html>
JavaScript Code::likedislikecntrl.js
var app=angular.module("myapp",["ngRoute"]);
app.controller("likedislikecntrl",function ($scope) {
var sirs=[
{name:"Srinivas",subject:"dmdw",gender:"male",likes:0,dislikes:0},
{name:"Sharif",subject:"dms",gender:"male",likes:0,dislikes:0},
{name:"Chaitanya",subject:"daa",gender:"male",likes:0,dislikes:0},
{name:"Pranav",subject:"wt",gender:"male",likes:0,dislikes:0},
{name:"Anil Chowdary",subject:"ds",gender:"male",likes:0,dislikes:0},
{name:"Rajesh",subject:"mp",gender:"male",likes:0,dislikes:0},
{name:"Deepak",subject:"dld",gender:"male",likes:0,dislikes:0},
{name:"JP",subject:"mp",gender:"male",likes:0,dislikes:0},
{name:"NagaDeepthi",subject:"oose",gender:"female",likes:0,dislikes:0},
{name:"Swathi",subject:"ca",gender:"female",likes:0,dislikes:0},
{name:"Madavilatha",subject:"cn",gender:"female",likes:0,dislikes:0}
]
$scope.sirs=sirs;
$scope.ldfi1=function (sir) {
sir.likes++
}
$scope.ldfd1=function (sir) {
sir.dislikes++
}
$scope.row=8;
})

Try this:
First change your controller
yourModuleName.controller("yourControllerName", function ($scope) {
var list = [
{ H1:'A', H2:'B', H3:'C', H4:'d' },
{ H1:'E', H2:'B', H3:'F', H4:'G' },
{ H1:'C', H2:'H', H3:'L', H4:'M' },
{ H1:'I', H2:'B', H3:'E', H4:'A' }
];
$scope.list = list;
$scope.headers = ["Header1", "Header2", "Header3", "Header4"];
$scope.sortColumn = 'Header1';
$scope.reverseSort = false;
$scope.sortData = function (columnIndex) {
$scope.reverseSort = ($scope.sortColumn == $scope.headers[columnIndex]) ? !$scope.reverseSort : false;
$scope.sortColumn = $scope.headers[columnIndex];
}
});
then change code in html side like this
<th ng-repeat= "header in headers">
<a ng-click="sortData($index)"> {{headers[$index]}} </a>
</th>
<tr ng-repeat "result in results | orderBy : sortColumn : reverseSort">
<td> {{results.h1}} </td>
<td> {{results.h2}} </td>
<td> {{results.h3}} </td>
<td> {{results.h4}} </td>
</tr>

Related

How the value is passed inside the indexOf()?

In this code, the 'm' is written inside the indexOf function. But no where in the code the value is passed. I am not able to understand how this 'm' deleting the right item in ng-repeat. When i change 'm' to something else it is now working. I am new to AngularJS.
In the main.js file there is removeitem function, i am getting from where the value of 'm' is coming , it has,nt passed from anywhere. I tried removeing 'm' but it doesnt work, it deletes the last item.
var app = angular.module('myApp', []);
app.controller('cont', function($scope) {
$scope.invoice = {
number: 10,
tax: 14,
items: [{
description: "",
quentity: 10,
cost: 300
}],
};
$scope.currency_symbol = [{
name: 'Indian Rupee',
currency: '₹'
},
{
name: 'USD',
currency: '$'
},
{
name: 'Euro',
currency: '€'
}
];
$scope.addItem = function() {
$scope.invoice.items.push([{
description: "description",
quentity: 1,
cost: 1
}]);
}
$scope.removeItem = function(m) {
$scope.invoice.items.splice($scope.invoice.items.indexOf(m), 1);
}
$scope.subTotal = function() {
var total = 0.0;
angular.forEach($scope.invoice.items, function(item, key) {
total += item.quentity * item.cost;
});
return total;
};
$scope.calcuteTax = function() {
return (($scope.subTotal() * $scope.invoice.tax) / 100);
};
$scope.grandTotal = function() {
return ($scope.subTotal() + $scope.calcuteTax());
};
});
<head>
<title>Simple Invoicing - Built with AngularJS </title>
<meta charset='utf-8'>
<meta name="description" content="AngularJS and Angular Code Example for creating Invoices and Invoicing Application">
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="css/style.css">
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js"></script>
</head>
<body ng-app="myApp" ng-controller="cont">
<div class="container" width="800px" id="invoice">
<div class="row">
<div class="col-xs-12 heading">
<strong>Billing System</strong>
</div>
</div>
</div>
<div class="main1">
<div="customer">
<select ng-init="currencySymbol=currency_symbol[0]" ng-model="currencySymbol" ng-options="currency.name+' '+currency.currency for currency in currency_symbol"></select>
</div>
</div>
<div class="main2">
<table border=1 width=100%>
<th></th>
<th>Description</th>
<th>Quantity</th>
<th>Cost{{' '+currencySymbol.currency}}</th>
<th>Total</th>
<tr ng-repeat="item in invoice.items">
<td text-align="center">
<a class="btn" href="" ng-click="removeItem()">
<strong>[x]</strong>
</a>
</td>
<td><input type="text" ng-model="item.description" placeholder="Description"></td>
<td><input type="number" ng-model="item.quentity" placeholder="10"></td>
<td><input type="number" ng-model="item.cost" placeholder="10"></td>
<td placeholder="0">{{item.quentity*item.cost}}</td>
</tr>
<tr>
<td text-align="center"><a class="btn" style="background-color:green;" href ng-click="addItem()">[+]</a></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td text-align="center"></td>
<td></td>
<td></td>
<td>Sub Total:</td>
<td>
<p>{{subTotal()}}</p>
</td>
</tr>
<tr>
<td text-align="center"></td>
<td></td>
<td></td>
<td>Tax:<input type="number" ng-model="invoice.tax"></td>
<td>
<p>{{calcuteTax()}}</p>
</td>
</tr>
<tr>
<td text-align="center"></td>
<td></td>
<td></td>
<td>Grand Total:</td>
<td>
<p>{{grandTotal()}}</p>
</td>
</tr>
</table>
</div>
</body>
How do i make the code delete the item on which i click ?
Add item as an argument to the removeItem function:
<tr ng-repeat="item in invoice.items">
<td text-align="center">
̶<̶a̶ ̶c̶l̶a̶s̶s̶=̶"̶b̶t̶n̶"̶ ̶h̶r̶e̶f̶=̶"̶"̶ ̶n̶g̶-̶c̶l̶i̶c̶k̶=̶"̶r̶e̶m̶o̶v̶e̶I̶t̶e̶m̶(̶)̶"̶>̶
<a class="btn" href="" ng-click="removeItem(item)">
<strong>[x]</strong>
</a>
</td>
$scope.removeItem = function(m) {
$scope.invoice.items.splice($scope.invoice.items.indexOf(m), 1);
}

How to change the index of the objects while sorting table

Can someone suggest me how to use angular filter for sorting the table by any column name, the sorting is working but the array index is not updating.
Thank you in advance
Please find the Pen
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope,$rootScope) {
$scope.orderByField = 'firstName';
$scope.reverseSort = false;
$rootScope.data = {
employees: [{
firstName: 'John',
lastName: 'Doe',
age: 30
},{
firstName: 'Frank',
lastName: 'Burns',
age: 54
},{
firstName: 'Sue',
lastName: 'Banter',
age: 21
}]
};
$scope.func=function(i){
console.log( $rootScope.data.employees[i]);
debugger;
}
});
section {
width: 400px;
margin: 10px auto;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.5/angular.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<section ng-app="app" ng-controller="MainCtrl">
<span class="label">Ordered By: {{orderByField}}, Reverse Sort: {{reverseSort}}</span><br><br>
<table class="table table-bordered">
<thead>
<tr>
<th>
<a href="#" ng-click="orderByField='firstName'; reverseSort = !reverseSort">
First Name <span ng-show="orderByField == 'firstName'"><span ng-show="!reverseSort">^</span><span ng-show="reverseSort">v</span></span>
</a>
</th>
<th>
<a href="#" ng-click="orderByField='lastName'; reverseSort = !reverseSort">
Last Name <span ng-show="orderByField == 'lastName'"><span ng-show="!reverseSort">^</span><span ng-show="reverseSort">v</span></span>
</a>
</th>
<th>
<a href="#" ng-click="orderByField='age'; reverseSort = !reverseSort">
Age <span ng-show="orderByField == 'age'"><span ng-show="!reverseSort" class="glyphicon glyphicon-triangle-top"></span><span class=" glyphicon glyphicon-triangle-bottom" ng-show="reverseSort"></span></span>
</a>
</th><th>Action</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="emp in data.employees|orderBy:orderByField:reverseSort">
<td>{{emp.firstName}}</td>
<td>{{emp.lastName}}</td>
<td>{{emp.age}}</td>
<td ng-click="func($index)" ><span class="glyphicon glyphicon-pencil"></span>edit</td>
</tr>
</tbody>
</table>
</section>
Having run the codepen/snippet I can see that clicking on edit doesn't log the appropriate row's employee.
You'll have to pass the employee to your handler rather than the index.
If you really need the index you can get the index using indexOf but using the index will just get you a reference to the same object so employee $rootScope.data.employees[i] are for all intents and purposes identical.
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope,$rootScope) {
$scope.orderByField = 'firstName';
$scope.reverseSort = false;
$rootScope.data = {
employees: [{
firstName: 'John',
lastName: 'Doe',
age: 30
},{
firstName: 'Frank',
lastName: 'Burns',
age: 54
},{
firstName: 'Sue',
lastName: 'Banter',
age: 21
}]
};
$scope.func=function(employee){
console.log(employee);
// if you absolutley need the index then use indexOf
var i = $rootScope.data.employees.indexOf(employee);
}
});
section {
width: 400px;
margin: 10px auto;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.5/angular.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<section ng-app="app" ng-controller="MainCtrl">
<span class="label">Ordered By: {{orderByField}}, Reverse Sort: {{reverseSort}}</span><br><br>
<table class="table table-bordered">
<thead>
<tr>
<th>
<a href="#" ng-click="orderByField='firstName'; reverseSort = !reverseSort">
First Name <span ng-show="orderByField == 'firstName'"><span ng-show="!reverseSort">^</span><span ng-show="reverseSort">v</span></span>
</a>
</th>
<th>
<a href="#" ng-click="orderByField='lastName'; reverseSort = !reverseSort">
Last Name <span ng-show="orderByField == 'lastName'"><span ng-show="!reverseSort">^</span><span ng-show="reverseSort">v</span></span>
</a>
</th>
<th>
<a href="#" ng-click="orderByField='age'; reverseSort = !reverseSort">
Age <span ng-show="orderByField == 'age'"><span ng-show="!reverseSort" class="glyphicon glyphicon-triangle-top"></span><span class=" glyphicon glyphicon-triangle-bottom" ng-show="reverseSort"></span></span>
</a>
</th><th>Action</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="emp in data.employees|orderBy:orderByField:reverseSort">
<td>{{emp.firstName}}</td>
<td>{{emp.lastName}}</td>
<td>{{emp.age}}</td>
<td ng-click="func(emp)" ><span class="glyphicon glyphicon-pencil"></span>edit</td>
</tr>
</tbody>
</table>
</section>

Angular table filtering with dynamic ng-model

I've done some basic Angular filtering but i encountered a little problem, and I don't know how to solve it. I have a table with heading with input. I want each input to filter the table by that column. The problem is trying to dynamically set ng-model to a corresponding column name. I can hard code it, but I need it dynamically. Has anyone done something like that before?
EDIT: Is there any way to sign key from ng-repeat to search[key] or something because i know interpolation doesn't work inside ng-model
Here is the code:
<table class="table table-striped">
<thead>
<tr ng-repeat="item in vm.students | limitTo:1">
<th ng-repeat="(key, val) in item">
{{key | format}}
</th>
</tr>
<tr ng-repeat="item in vm.students | limitTo:1">
<th ng-repeat="(key, val) in item">
<input type="text" ng-model='search.key'>
</th>
<tr>
</thead>
<tbody>
<tr ng-repeat="item in vm.students | filter:search.key ">
<td> {{item.id}}</td>
<td> {{item.car}}</td>
<td> {{item.payment_method}}</td>
<td> {{item.currency}}</td>
<td> {{item.city}}</td>
</tr>
</tbody>
<tfoot>
</tfoot>
</table>
You can use Object.keys() method to populate an array of columns to generate your table and then use a search object for filtering, from the docs:
A pattern object can be used to filter specific properties on objects
contained by array. For example {name:"M", phone:"1"} predicate will
return an array of items which have property name containing "M" and
property phone containing "1".
Here is an example:
angular.module('app', [])
.controller('mainController', function mainController($scope) {
$scope.students = [
{ name: 'Aaron Judge', year: 'one', mark: 98 },
{ name: 'Ryan Zimmerman', year: 'two', mark: 76 },
{ name: 'Paul Goldschmidt', year: 'one', mark: 87 },
{ name: 'Mike Trout', year: 'two', mark: 89 },
{ name: 'Charlie Blackmon', year: 'one', mark: 77 },
{ name: 'Bryce Harper', year: 'three', mark: 67 },
{ name: 'Jose Altuve', year: 'two', mark: 83 },
];
$scope.columns = Object.keys($scope.students[0]);
$scope.search = {};
});
body { padding-top:50px; }
table input { color: black; }
<!-- CSS -->
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootswatch/3.2.0/sandstone/bootstrap.min.css">
<!-- JS -->
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.js"></script>
<body ng-app="app">
<div class="container" ng-controller="mainController">
<div class="alert alert-info">
<h2>Students ({{search}})</h2>
<table class="table table-bordered">
<thead>
<tr>
<th ng-repeat="column in columns track by column">{{ column }}</th>
</tr>
<tr>
<th ng-repeat="column in columns track by column">
<input type="text" ng-model="search[column]">
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="student in students | filter:search track by student.name">
<td ng-repeat="column in columns track by column">{{ student[column] }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
Simple example of sorting table as per column , this can be improved by using custom filters also , this is basic example
<html>
<head>
<title>Angular JS</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js">
</script>
<script>
var myApp = angular.module("myApp", []);
myApp.controller("firstCtrl", function($scope) {
$scope.books = [{
name: "Angular",
authur: "James",
price: 500,
year: 2012
}, {
name: "Java",
authur: "Durga",
price: 700,
year: 2001
}, {
name: "HTML",
authur: "Rahul",
price: 1500,
year: 2011
}, {
name: "CSS",
authur: "Anand",
price: 2500,
year: 2002
}, {
name: "Node",
authur: "Rade",
price: 550,
year: 2015
}];
});
</script>
</head>
<body>
<div ng-app="myApp">
<div ng-controller="firstCtrl">
<table border="1">
<tr>
<th >Name</th>
<th>Authur</th>
<th >Price</th>
<th>Year</th>
</tr>
<tr>
<td>
<input type="text" ng-model="filterWithName" />
</td>
<td>
<input type="text" ng-model="filterWithAuthur"/>
</td>
<td>
<input type="text" ng-model="filterWithPrice" />
</td>
<td>
<input type="text" ng-model="filterWithYear" />
</td>
</tr>
<tr ng-repeat="book in books | filter:{name:filterWithName,authur:filterWithAuthur,price:filterWithPrice,year:filterWithYear}">
<td>{{book.name}}</td>
<td>{{book.authur}}</td>
<td>{{book.price}}</td>
<td>{{book.year}}</td>
</tr>
</table>
</div>
</div>
</body>
</html>

Select child checkbox on click of parent checkbox angularjs

I would like to know how to select the child checkboxes when parent checkbox is selected. In the below plunkr i have parent checkbox in table head and child checkboxes in table body. On click of parent checkbox in table head i want all the child checkboxes in table body to be selected and when all the child checkboxes in table body are selected parent checkbox in table head also should be selected. Here is the plunkr - https://plnkr.co/edit/9wWxczEH22aG71RN3B0Q?p=preview
html code-
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="script.js"></script>
<body ng-app="test" ng-controller="test">
<table style="width:100%;overflow: scroll; border: 2px solid #AAA; ">
<thead style="border-bottom: 1px solid #AAA">
<tr>
<th style="width:50%"> <input type='checkbox'/> catalog</th>
<th style="width:25%">currentVersion</th>
<th style="width:25%">new Version</th>
</tr>
</thead>
<tbody style="color: #007db8;">
<tr ng-repeat="item in items" ng-attr-id="item.id">
<td style="width:50%">
<input type='checkbox' ng-model="dummyModel[item.id]" ng-change="selectItem(item)"/> {{ item.catalog }}
</td>
<td style="width:25%">{{ item.currentVersion }}</td>
<td style="width:25%">{{ item.newVersion }}</td>
</tr>
</tbody>
</table>
<button style="font-size: 11px;" type="button" class="btn btn-primary" ng-click="update()" >Update</button>
</body>
Here you go:
angular.module('test', [])
.controller('test', function($scope) {
$scope.selectAll = false;
$scope.itemSelecteds = {};
$scope.dummyModel = {};
$scope.items = [{
id: '1',
name: 'mit',
catalog: 'Multiple',
currentVersion: '1.2',
newVersion: '1.3',
}, {
id: '2',
name: 'mit',
catalog: 'Multiple',
currentVersion: '1.2',
newVersion: '1.3',
}, {
id: '3',
name: 'mit',
catalog: 'Multiple',
currentVersion: '1.2',
newVersion: '1.3',
}];
$scope.selectAllItem = function() {
// Delete the selection
$scope.dummyModel = {};
$scope.itemSelecteds = {};
// If select all checkbox is checked, then mark all items as selected
if ($scope.selectAll) {
angular.forEach($scope.items, function(item) {
this[item.id] = angular.copy(item);
$scope.dummyModel[item.id] = true;
}, $scope.itemSelecteds);
}
};
$scope.selectItem = function(item) {
// If checkbox is checked
if ($scope.dummyModel[item.id]) {
$scope.itemSelecteds[item.id] = item;
} else {
delete $scope.itemSelecteds[item.id];
}
// If all items are selected, mark selectAll as true
$scope.selectAll = ((Object.keys($scope.itemSelecteds)).length === $scope.items.length);
}
$scope.update = function() {
console.log($scope.itemSelecteds);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="test" ng-controller="test">
<table style="width:100%;overflow: scroll; border: 2px solid #AAA; ">
<thead style="border-bottom: 1px solid #AAA">
<tr>
<th style="width:50%">
<input type='checkbox' ng-model='selectAll' ng-change='selectAllItem()' /> catalog</th>
<th style="width:25%">currentVersion</th>
<th style="width:25%">new Version</th>
</tr>
</thead>
<tbody style="color: #007db8;">
<tr ng-repeat="item in items" ng-attr-id="item.id">
<td style="width:50%">
<input type='checkbox' ng-model="dummyModel[item.id]" ng-change="selectItem(item)" /> {{ item.catalog }}
</td>
<td style="width:25%">{{ item.currentVersion }}</td>
<td style="width:25%">{{ item.newVersion }}</td>
</tr>
</tbody>
</table>
<button style="font-size: 11px;" type="button" class="btn btn-primary" ng-click="update()">Update</button>
</body>

how to have a popup child tr for every tr element on ng-click

I have a table which using ng-repeat
<table>
<thead>
<tr>
<th>Assets</th>
<th>Location</th>
<th>Size</th>
<th>Price</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr id="parent" data-ng-repeat="assets in vm.employees"
data-toggle="collapse" id="row{{$index}}" data-target=".row{{$index}}">
<td class="name">
<i class="mdi mdi-plus s16" ng-click="childRowToggle($event)"></i>
{{assets.name}}
<span class="secondary-text">{{assets.code}}</span>
</td>
<td>{{assets.location}}</td>
<td>{{assets.size}}</td>
<td>{{assets.price}}</td>
</tr>
<tr id="child" data-ng-repeat="assets in vm.employees" class="collapse row{{$index}}">
<div>i' have to be shown under every tr element when clicks
</tr>
</tbody>
</table>
If i click on the i element which is in parent tr, i want the child tr popup under that tr element. i already tried something like this
$scope.childRowToggle = function($event){
$('#childrow').remove();
var $this = $($event.target);
var $obj =$this.parent().parent();
console.log($obj.attr('class'));
$("<tr id='childrow'><td colspan='5'>Dummy Data</td></tr>").insertAfter($obj);
}
Here is a working version: https://jsfiddle.net/Shitsu/c6bj75mp/.
angular.module('myApp', []).controller('Ctrl',
function($scope) {
$scope.employees = [{
name: "lala",
location: "loc",
size: 10,
price: 44
}, {
name: "lala",
location: "loc",
size: 10,
price: 44
}, {
name: "lala",
location: "loc",
size: 10,
price: 44
}, {
name: "lala",
location: "loc",
size: 10,
price: 44
}, {
name: "lala",
location: "loc",
size: 10,
price: 44
}];
});
.noPadding {
padding: 0 !important;
}
td p {
padding: 10px;
margin: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="Ctrl">
<table class="table table-condensed" style="border-collapse:collapse;">
<thead>
<tr>
<th>Assets</th>
<th>Location</th>
<th>Size</th>
<th>Price</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat-start="assets in employees track by $index" data-toggle="collapse" data-target="#row-{{$index}}" class="accordion-toggle">
<td class="name">
<i class="mdi mdi-plus s16">{{assets.name}}</i>
<span class="secondary-text">{{assets.code}}</span>
</td>
<td>{{assets.location}}</td>
<td>{{assets.size}}</td>
<td>{{assets.price}}</td>
</tr>
<tr ng-repeat-end>
<td colspan="5" class="noPadding">
<div class="accordian-body collapse collapsible" id="row-{{$index}}">
<p>
Collapsed datas
</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
Have you thought of using tooltips ? UI-Bootstrap has really nice tooltips which would do exactly what you want. You can choose if you trigger the tooltip on hover or on click. Have a look at this fiddle.
HTML:
<!doctype html>
<html ng-app="App">
<body ng-controller="Ctrl">
<table>
<tr ng-repeat="a in assets">
<td tooltip-html-unsafe="{{a}}<br />blabla" tooltip-placement="bottom">{{a}}</td>
</tr>
</table>
</body>
</html>
JS:
angular.module('App', ['ui.bootstrap'])
.controller('Ctrl', function($scope) {
$scope.assets = ['a', 'b', 'c'];
});

Resources