(function() {
'use strict';
angular.module('sampleApp', ['ngMaterial', 'material.components.table']);
})();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>angular material multiple select</title>
<meta content="marcusasplund.com" name="author">
<meta content="width=device-width, initial-scale=1" name="viewport">
<script>
document.write('<base href="' + document.location + '"/>');
</script>
<link href="//ajax.googleapis.com/ajax/libs/angular_material/0.9.4/angular-material.min.css" rel="stylesheet">
<link href="//fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="//fonts.googleapis.com/css?family=RobotoDraft:300,400,500,700,400italic" rel="stylesheet">
<link href="material-icons.css" rel="stylesheet">
<link href="md-table.css" rel="stylesheet">
<link href="sample.css" rel="stylesheet">
</head>
<body layout="column" ng-app="sampleApp" ng-controller="sampleController" flex>
<md-toolbar layout="column" class="md-small md-hue-2">
<div class="md-toolbar-tools">
<div layout="row" flex>
<!-- Blank -->
<span flex ng-show="!toggleSearch"></span>
<!-- Search bar -->
<md-input-container ng-show="toggleSearch" style="padding-left:88px" flex>
<input type="text" ng-model="filterValue" aria-label="filter">
</md-input-container>
</div>
<!-- Search icon -->
<div class="md-toolbar-item md-tools">
<md-button ng-click="toggleSearch = !toggleSearch">
<i class="material-icons md-18">search</i>
</md-button>
</div>
</div>
</md-toolbar>
<md-table headers-class="headerClass" contents-class="contentClass"
headers="headers" contents="contents"
pagination="true" page-count="pageItems"
action="true" on-action="deleteOperation(selectedContent, $event)"
selection="true" on-select="selectOperation(checked, selectedContent)"
filter="filterValue">
</md-table>
<!-- Angular JS + AngularJS Material -->
<script data-require="angular.js@1.4.x" src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.js" data-semver="1.4.0-rc.0"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular-animate.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular-aria.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angular_material/0.9.4/angular-material.min.js"></script>
<!-- md-table -->
<script src="md-table.js"></script>
<!-- Sample -->
<script src="app.js"></script>
<script src="sampleController.js"></script>
</body>
</html>
/**
*
*/
.md-table {
min-width: 100%;
border-collapse: collapse;
}
.md-table tbody tr:hover, .md-table tbody tr:focus {
cursor:pointer;
background-color:rgba(0,0,0,0.03);
}
.md-table-header {
border-bottom: 1px solid rgb(230,230,230);
color: rgb(130,130,130);
text-align: left;
font-size: 0.75em;
font-weight: 700;
padding: 0px 0px 0px 0px;
}
.md-table-header a {
margin-left: 15px;
text-decoration: none;
color: inherit;
}
.md-table-td-check {
width: 40px;
}
.md-table-td-more {
width: 40px;
}
.md-button.md-default-theme.md-action {
border-radius: 50%;
z-index: 20;
width: 36px;
height: 36px;
border-radius: 50%;
border-radius: 50%;
overflow: hidden;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
-webkit-transition: 0.2s linear;
transition: 0.2s linear;
-webkit-transition-property: -webkit-transform, box-shadow;
transition-property: transform, box-shadow;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
}
.md-table-header .unsorted {
margin-right: 24px;
}
.md-table-caret {
display: inline-block;
vertical-align: middle;
}
.md-table-content {
font-size: 0.9em;
padding: 15px 15px 15px 15px;
}
.md-table-footer {
margin: 0px 20px 0px 20px;
height:40px;
}
.md-table-count-info {
line-height:40px;
font-size:.75em;
}
.md-table-footer-item {
width: 40px;
height: 40px;
vertical-align:middle;
}
.md-table-page-link {
text-decoration: none;
}
.md-table-active-page {
font-weight: 700;
}
(function () {
/**
*
*/
'use strict';
angular.module('material.components.table', ['material.core']).controller('mdTableController', [
'$scope', '$filter', mdTableController
]).directive('mdTable', mdTableDirective).filter('pageFilter', mdTablePageFilter).filter('contentFilter', [
'$filter', mdTableContentFilter
]);
/**
* Create md-table Directive
*/
function mdTableDirective() {
return {
restrict : 'E',
scope : {
action : '&onAction',
contentFilter : '=filter',
contents : '=',
contentsClass : '=',
enableAction : '=action',
enablePagination: '=pagination',
enableSelection : '=selection',
headers : '=',
headersClass : '=',
pageCount : '=?',
select : '&onSelect'
},
link : mdTableLink,
controller : mdTableController,
templateUrl: 'mdTable.html'
};
}
/**
* Create mdTableController
*
* @param {type} $scope
* @param {type} $filter
* @returns {undefined}
*/
function mdTableController($scope, $filter) {
initializeControllerDatas($scope);
initializePagination($scope);
$scope.$watchCollection(function () {
return $scope.contents;
}, function () {
initializePagination($scope);
});
/**
* Sorting content
*/
$scope.sort = function (predicate, reverse) {
$scope.reverse = !reverse;
$scope.contents = $filter('orderBy')($scope.contents, predicate, $scope.reverse);
$scope.predicate = predicate;
};
/**
* Display next page
*/
$scope.next = function () {
$scope.currentPage = $scope.currentPage + 1;
};
/**
* Display previous page
*/
$scope.previous = function () {
$scope.currentPage = $scope.currentPage - 1;
};
/**
* Determine if "Previous" button is enable
*/
$scope.previousDisabled = function () {
return $scope.currentPage === 0;
};
/**
* Determine if "Next" button is enable
*/
$scope.nextDisabled = function () {
return $scope.pages.length === 0 || $scope.currentPage === ($scope.pages.length - 1);
};
/**
* Select the page
*/
$scope.selectPage = function (pageIndex) {
$scope.currentPage = pageIndex;
};
/* TODO Not implemented yet
$scope.selectAll = function(checked) {
checked = !checked;
console.log(checked);
}
*/
$scope.nbOfPages = function () {
return Math.ceil($scope.content.length / $scope.pageItems);
};
}
/**
* Create mdTableLink
*/
function mdTableLink($scope, $element, $attr) {
$element.attr({
'role': 'table'
});
}
/**
* @return The filter use to paginate
*/
function mdTablePageFilter() {
return function (contents, selectedPage) {
selectedPage = +selectedPage;
if (contents) {
return contents.slice(selectedPage);
} else {
return '';
}
};
}
/**
* @return The filter use to paginate
*/
function mdTableContentFilter($filter) {
var result;
return function (value, contentFilter) {
if (contentFilter) {
if (contentFilter.pattern) {
result = $filter(contentFilter.filter)(value, contentFilter.pattern);
return result;
} else {
result = $filter(contentFilter.filter)(value);
return result;
}
} else {
return value;
}
};
}
/**
* Initialization of controller's data
*/
function initializeControllerDatas($scope) {
// Sorting
$scope.reverse = true;
$scope.predicate = '';
// Pagination
$scope.currentPage = 0;
initializePagination($scope);
}
/**
* Determine the number of pages
*
* @return Pages representing by an array
*/
function initializePagination($scope) {
var contents = $scope.contents;
var pages = [];
if (contents) {
if (!$scope.pageCount) {
$scope.pageCount = contents.length;
}
var numberOfPages = Math.ceil(contents.length / $scope.pageCount);
for (var i = 0; i < numberOfPages; i++) {
pages.push({
index: i,
name : 'page' + i
});
}
}
$scope.pages = pages;
}
/**
* This method help to create an header object
*
* @param label
* Label of the header (Mandatory)
* @param contentField
* Link with the content's field (Mantadory)
* @param contentType
* Nature of content's field (Default => 'text' :
* - 'input'
* - 'text'
* - 'image'
* @param sortableField
* Flag to indicate if the field is sortable
*/
function mdTableHeader(label, contentField, contentType, sortableField) {
this.label = label;
this.contentField = contentField;
this.contentType = contentType || 'text';
this.sortableField = sortableField || false;
}
/**
* This method help to create a content object
*
* @param data
* Content data's (Mandatory)
*/
function mdTableContent(data) {
this.data = data;
}
})();
(function () {
'use strict';
angular.module('sampleApp').controller('sampleController', [
'$scope', '$filter', '$mdBottomSheet', SampleController
]);
function SampleController($scope, $filter, $mdBottomSheet) {
$scope.value = 'Hello Angular';
$scope.pageItems = 6;
$scope.hello = function () {
alert('Hello AngularJS Material !');
};
$scope.selectedContent = '';
$scope.headerClass = {
amount: 'table-amount-content',
date : 'table-date-content',
label : 'fill-content'
};
$scope.contentClass = {
amount: 'grey',
date : 'bold',
label : 'grey'
};
$scope.headers = initHeaders();
$scope.loadDatas = function () {
$scope.contents = initContent();
};
$scope.loadDatas();
$scope.deleteOperation = function (selectedContent, $event) {
$mdBottomSheet.show({
controller : function ($scope) {
$scope.deleteItem = function () {
$mdBottomSheet.hide();
};
},
targetEvent: $event,
template : '<md-bottom-sheet class="md-grid"><span flex></span><md-button aria-label="Delete" ng-click="deleteItem()"><i class="material-icons md-18">delete</i></md-button></md-bottom-sheet>'
}).then(function () {
console.log(selectedContent);
});
};
$scope.selectOperation = function (checked, selectedContent) {
console.log('Is it checked ? ' + checked);
console.log(selectedContent);
};
}
function initHeaders() {
return [
{
contentField : 'date',
contentFilter: {
filter : 'date',
pattern: 'dd/MM/yyyy'
},
contentType : 'text',
label : 'Date',
sortableField: true
}, {
contentField : 'label',
contentFilter: {
filter: 'uppercase'
},
contentType : 'text',
label : 'Label',
sortableField: true
}, {
contentField : 'amount',
contentType : 'input',
label : 'Amount',
sortableField: true
}
];
}
function initContent() {
return [
{
amount: 10.0,
date : new Date().getMilliseconds(),
label : 'Task 1'
}, {
amount: 20.0,
date : new Date().getMilliseconds(),
label : 'Task 2'
}, {
amount: 90.0,
date : new Date().getMilliseconds(),
label : 'Task 3'
}, {
amount: 60.0,
date : new Date().getMilliseconds(),
label : 'Task 4'
}, {
amount: 70.0,
date : new Date().getMilliseconds(),
label : 'Task 5'
}, {
amount: 30.0,
date : new Date().getMilliseconds(),
label : 'Task 6'
}, {
amount: 50.0,
date : new Date().getMilliseconds(),
label : 'Task 7'
}, {
amount: 80.0,
date : new Date().getMilliseconds(),
label : 'Task 8'
}, {
amount: 5.0,
date : new Date().getMilliseconds(),
label : 'Task 9'
}
];
}
})();
.md-table-headers-row {
height: 70px;
vertical-align: middle;
}
.table-date-content {
min-width: 105px;
width: 105px;
}
.fill-content {
width: auto;
}
.table-amount-content {
min-width: 110px;
width: 110px;
}
.bold {
font-weight: 700;
}
.grey {
color: grey;
}
*:focus{
outline: 0;
}
md-input-container.md-default-theme .md-input {
color: white;
border-color: white;
margin-top: 24px;
}
body {
font-family: 'RobotoDraft';
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px; /* Preferred icon size */
display: inline-block;
width: 1em;
height: 1em;
line-height: 1;
text-transform: none;
/* Support for all WebKit browsers. */
-webkit-font-smoothing: antialiased;
/* Support for Safari and Chrome. */
text-rendering: optimizeLegibility;
/* Support for Firefox. */
-moz-osx-font-smoothing: grayscale;
/* Support for IE. */
font-feature-settings: 'liga';
}
.material-icons.md-18 { font-size: 18px; }
.material-icons.md-24 { font-size: 24px; }
.material-icons.md-36 { font-size: 36px; }
.material-icons.md-48 { font-size: 48px; }
.material-icons.md-dark { color: rgba(0, 0, 0, 0.54); }
.material-icons.md-dark.md-inactive { color: rgba(0, 0, 0, 0.26); }
.material-icons.md-light { color: rgba(255, 255, 255, 1); }
.material-icons.md-light.md-inactive { color: rgba(255, 255, 255, 0.3); }
<div>
<table class="md-table">
<!-- Header -->
<thead>
<tr class="md-table-headers-row">
<!-- Multiple selection -->
<th class="md-table-header" ng-show="enableSelection">
<md-checkbox aria-label="Select all" on-change="selectAll(checked)"></md-checkbox>
</th>
<!-- Content -->
<th class="md-table-header" ng-class="headersClass[header.contentField]"
ng-repeat="header in headers">
<!-- Sortable Field -->
<a href ng-click="sort(header.contentField, reverse);"
ng-if="header.sortableField">
{{header.label}}
<span class="md-table-caret"
ng-show="reverse && header.contentField == predicate">
<i class="material-icons md-18">arrow_drop_up</i>
</span>
<span class="md-table-caret"
ng-show="!reverse && header.contentField == predicate">
<i class="material-icons md-18">arrow_drop_down</i>
</span>
<span class="unsorted" ng-show="!(header.contentField == predicate)"></span>
</a>
<!-- Unsortable Field -->
<span ng-if="!header.sortableField">
{{header.label}}
</span>
</th>
<!-- Actions -->
<th class="md-table-header" ng-show="enableAction"></tr>
</thead>
<!-- Body -->
<tbody>
<tr class="md-table-content-row"
ng-repeat="content in contents | filter: contentFilter | pageFilter: currentPage
* pageCount | limitTo: pageCount">
<!-- Selection -->
<td class="md-table-td-check" ng-show="enableSelection">
<md-checkbox aria-label="Select content"
ng-change="select({checked: checkedValue, selectedContent: content})" ng-model="checkedValue"></md-checkbox>
</td>
<!-- Content -->
<td ng-model="header" ng-repeat="header in headers">
<div ng-switch="header.contentType">
<!-- Thumb -->
<div class="md-table-thumbs" ng-switch-when="image">
<div style="background-image:url({{content[header.contentField]}})"></div>
</div>
<!-- Input -->
<div class="md-table-content" ng-switch-when="input">
<md-input-container flex>
<input aria-label="input" ng-model="content[header.contentField]" type="text" style="color:#000"/>
</md-input-container>
</div>
<!-- Text -->
<div class="md-table-content" ng-class="contentsClass[header.contentField]"
ng-switch-when="text">
{{content[header.contentField] | contentFilter : header.contentFilter}}
</div>
</div>
</td>
<!-- Actions -->
<td class="md-table-td-more" ng-show="enableAction">
<md-button aria-label="Action" ng-click="action({selectedContent: content})">
<i class="material-icons md-18">more_vert</i>
</md-button>
</td>
</tr>
</tbody>
</table>
<!-- Footer / Pagination -->
<div class="md-table-footer" layout="row">
<span class="md-table-count-info">Rows per page : <a href="#" ng-click="goToPage(0); pageItems=10">10</a> <a href="#" ng-click="goToPage(0); pageItems=25">25</a> <a href="#" ng-click="goToPage(0); pageItems=50">50</a> <a href="#" ng-click="goToPage(0); pageItems=100">100</a>(current is {{pageItems}})</span><span flex="flex"></span>
<span flex></span>
<span ng-show="enablePagination">
<!-- Previous page -->
<md-button aria-label="Previous" class="md-table-footer-item" ng-click="previous()"
ng-disabled="previousDisabled();">
<i class="material-icons md-18">keyboard_arrow_left</i>
</md-button>
<!-- Current page selection -->
<a class="md-table-page-link" href ng-repeat="page in pages">
<md-button aria-label="Index" class="md-primary md-table-footer-item"
ng-click="selectPage(page.index)">
<span ng-class="{'md-table-active-page': currentPage == page.index}">{{page.index}}</span>
</md-button>
</a>
<!-- Next page -->
<md-button aria-label="Next" class="md-table-footer-item" ng-click="next()"
ng-disabled="nextDisabled();">
<i class="material-icons md-18">keyboard_arrow_right</i>
</md-button>
</span>
</div>
</div>