New grid component vnTable. #139. CR: Juan & Javi
This commit is contained in:
parent
fb07f5e860
commit
45b3a5ce02
|
@ -37,3 +37,5 @@ import './paging/paging';
|
|||
import './auto-paging/auto-paging';
|
||||
import './pagination/pagination';
|
||||
import './searchbar/searchbar';
|
||||
import './table';
|
||||
import './th';
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<div></div>
|
|
@ -0,0 +1,53 @@
|
|||
import ngModule from '../../module';
|
||||
import './style.scss';
|
||||
|
||||
export default class Table {
|
||||
constructor($scope, $element, $transclude) {
|
||||
this.$scope = $scope;
|
||||
this.table = $element[0];
|
||||
this.field = null;
|
||||
this.order = null;
|
||||
|
||||
$transclude($scope.$parent, clone => {
|
||||
angular.element($element[0].querySelector('div')).append(clone);
|
||||
});
|
||||
}
|
||||
|
||||
setOrder(field, order) {
|
||||
this.field = field;
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
applyFilter(field = this.field, order = this.order) {
|
||||
this.model.filter.order = `${field} ${order}`;
|
||||
this.model.refresh();
|
||||
this.setActiveArrow();
|
||||
}
|
||||
|
||||
$onChanges() {
|
||||
if (this.model)
|
||||
this.applyFilter();
|
||||
}
|
||||
|
||||
setActiveArrow() {
|
||||
let columns = this.table.querySelectorAll('vn-thead vn-th');
|
||||
columns.forEach(column => {
|
||||
column.classList.remove('active');
|
||||
});
|
||||
|
||||
let selector = `vn-thead vn-th[field="${this.field}"]`;
|
||||
let activeColumn = this.table.querySelector(selector);
|
||||
activeColumn.classList.add('active');
|
||||
}
|
||||
}
|
||||
|
||||
Table.$inject = ['$scope', '$element', '$transclude'];
|
||||
|
||||
ngModule.component('vnTable', {
|
||||
template: require('./index.html'),
|
||||
transclude: true,
|
||||
controller: Table,
|
||||
bindings: {
|
||||
model: '<?'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,117 @@
|
|||
@import "effects";
|
||||
|
||||
vn-table {
|
||||
border-collapse: collapse;
|
||||
display: table;
|
||||
width: 100%;
|
||||
|
||||
& > div {
|
||||
width: 100%;
|
||||
display: table;
|
||||
|
||||
vn-thead {
|
||||
display: table-header-group;
|
||||
|
||||
vn-th[field] {
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
vn-th[field] > * {
|
||||
padding-right: 20px
|
||||
}
|
||||
|
||||
vn-th[field] > :after {
|
||||
font-family: 'Material Icons';
|
||||
content: 'arrow_drop_down';
|
||||
position: absolute;
|
||||
padding-left: 2px;
|
||||
color: $lines;
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
vn-th[field] > :hover:after {
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
vn-th[field].active > :after {
|
||||
color: $main-font-color;
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
vn-th[field].desc > :after {
|
||||
content: 'arrow_drop_down';
|
||||
}
|
||||
|
||||
vn-th[field].asc > :after {
|
||||
content: 'arrow_drop_up';
|
||||
}
|
||||
}
|
||||
|
||||
vn-tbody {
|
||||
display: table-row-group
|
||||
}
|
||||
|
||||
vn-tfoot {
|
||||
display: table-footer-group
|
||||
}
|
||||
|
||||
vn-tr {
|
||||
display: table-row
|
||||
}
|
||||
|
||||
vn-empty-rows {
|
||||
display: table-caption;
|
||||
caption-side: bottom;
|
||||
text-align: center;
|
||||
padding: 10px
|
||||
}
|
||||
|
||||
vn-thead,
|
||||
vn-tbody,
|
||||
vn-tfoot {
|
||||
vn-tr {
|
||||
display: table-row;
|
||||
|
||||
vn-th {
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
vn-td, vn-th {
|
||||
display: table-cell;
|
||||
text-align: left;
|
||||
padding: 10px;
|
||||
|
||||
&[number]{
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vn-thead, vn-tbody, vn-empty-rows {
|
||||
border-bottom: 3px solid $lines;
|
||||
}
|
||||
vn-tbody > vn-tr {
|
||||
border-bottom: 1px solid $lines;
|
||||
transition: background-color 200ms ease-in-out;
|
||||
|
||||
&.clickable {
|
||||
@extend %clickable;
|
||||
}
|
||||
&.success {
|
||||
background-color: rgba(163, 209, 49, 0.3);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(163, 209, 49, 0.5);
|
||||
}
|
||||
}
|
||||
&.warning {
|
||||
background-color: rgba(247, 147, 30, 0.3);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(247, 147, 30, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<div translate ng-click="$ctrl.onToggleOrder()">
|
||||
<ng-transclude></ng-transclude>
|
||||
</div>
|
|
@ -0,0 +1,84 @@
|
|||
import ngModule from '../../module';
|
||||
|
||||
export default class Th {
|
||||
constructor($element) {
|
||||
this.column = $element[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the order if the cell has a field and defaultOrder property
|
||||
*/
|
||||
$onInit() {
|
||||
if (!this.field) return;
|
||||
|
||||
if (this.defaultOrder)
|
||||
this.order = this.defaultOrder;
|
||||
|
||||
this.updateArrow();
|
||||
}
|
||||
|
||||
set order(order) {
|
||||
this._order = order;
|
||||
|
||||
this.table.setOrder(this.field, order);
|
||||
}
|
||||
|
||||
get order() {
|
||||
return this._order;
|
||||
}
|
||||
|
||||
get field() {
|
||||
return this.column.getAttribute('field');
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle order ASC/DESC
|
||||
*/
|
||||
toggleOrder() {
|
||||
if (this.order === 'ASC') {
|
||||
this.order = 'DESC';
|
||||
} else {
|
||||
this.order = 'ASC';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a new filter order to the model and
|
||||
* updates the cell arrow
|
||||
*/
|
||||
onToggleOrder() {
|
||||
if (!this.field) return;
|
||||
|
||||
this.toggleOrder();
|
||||
this.updateArrow();
|
||||
|
||||
this.table.applyFilter(this.field, this.order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cell class to asc/desc
|
||||
*/
|
||||
updateArrow() {
|
||||
this.column.classList.remove('asc', 'desc');
|
||||
|
||||
if (this.order === 'DESC') {
|
||||
this.column.classList.add('desc');
|
||||
} else {
|
||||
this.column.classList.add('asc');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Th.$inject = ['$element'];
|
||||
|
||||
ngModule.component('vnTh', {
|
||||
template: require('./index.html'),
|
||||
transclude: true,
|
||||
controller: Th,
|
||||
bindings: {
|
||||
defaultOrder: '@?'
|
||||
},
|
||||
require: {
|
||||
table: '^^vnTable'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,60 @@
|
|||
import './index.js';
|
||||
import template from './index.html';
|
||||
|
||||
fdescribe('Component vnTh', () => {
|
||||
let $componentController;
|
||||
let controller;
|
||||
let $element;
|
||||
|
||||
beforeEach(() => {
|
||||
angular.mock.module('client');
|
||||
});
|
||||
|
||||
beforeEach(angular.mock.inject(_$componentController_ => {
|
||||
$componentController = _$componentController_;
|
||||
$element = angular.element(`<div>${template}</div>`);
|
||||
controller = $componentController('vnTh', {$element: $element});
|
||||
controller.table = {setOrder: () => {}};
|
||||
controller.column = {
|
||||
getAttribute: () => 'MyField',
|
||||
classList: {
|
||||
add: () => {},
|
||||
remove: () => {}
|
||||
}
|
||||
};
|
||||
}));
|
||||
|
||||
describe('toggleOrder()', () => {
|
||||
it(`should change the ordenation to DESC (descendant) if it was ASC (ascendant)`, () => {
|
||||
controller.order = 'ASC';
|
||||
controller.toggleOrder();
|
||||
|
||||
expect(controller.order).toEqual('DESC');
|
||||
});
|
||||
|
||||
it(`should change the ordenation to ASC (ascendant) if it wasnt ASC`, () => {
|
||||
controller.order = 'DESC or any other value that might occur';
|
||||
controller.toggleOrder();
|
||||
|
||||
expect(controller.order).toEqual('ASC');
|
||||
});
|
||||
|
||||
it(`should call the setOrder() function after changing a value`, () => {
|
||||
spyOn(controller.table, 'setOrder');
|
||||
controller.order = 'Change me!';
|
||||
|
||||
expect(controller.table.setOrder).toHaveBeenCalledWith('MyField', 'Change me!');
|
||||
});
|
||||
});
|
||||
|
||||
describe('onInit()', () => {
|
||||
it(`should define controllers order as per defaultOrder then call setOrder()`, () => {
|
||||
controller.defaultOrder = 'DESC';
|
||||
spyOn(controller.table, 'setOrder');
|
||||
controller.$onInit();
|
||||
|
||||
expect(controller.order).toEqual('DESC');
|
||||
expect(controller.table.setOrder).toHaveBeenCalledWith('MyField', 'DESC');
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue