Compare commits
40 Commits
production
...
develop
Author | SHA1 | Date | |
---|---|---|---|
263f7cad77 | |||
eea71c930e | |||
f630fa677f | |||
3dbb712260 | |||
7830d08332 | |||
acbaff4428 | |||
c983cd9ef6 | |||
ca75517a53 | |||
16f1cc996a | |||
6108cf9398 | |||
1dd363ce37 | |||
71e39dd9d8 | |||
2523cdacbf | |||
8a51ebf22d | |||
e1bd8398b6 | |||
7d2f00cf4e | |||
3e544ee2ef | |||
8d3c235758 | |||
2ab53cacaa | |||
d92d0dc7a5 | |||
e110382ce5 | |||
e85c9e52fc | |||
7345e2ed27 | |||
b8960b0eb2 | |||
a1418306fa | |||
fd552d1ea8 | |||
f21e120e00 | |||
2258c12b56 | |||
fe566961ce | |||
76bb80d159 | |||
9430642b5d | |||
da9e3960e2 | |||
7ee1eda2f0 | |||
d544581b0e | |||
feda2b6c53 | |||
0fb93f723e | |||
dc6ee49467 | |||
5f5abe7fc2 | |||
bbe41ef0b5 | |||
d96ff93076 |
@ -1,46 +0,0 @@
|
|||||||
version: 2
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
docker:
|
|
||||||
- image: circleci/node:10.4-browsers
|
|
||||||
|
|
||||||
working_directory: ~/repo
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
|
|
||||||
- restore_cache:
|
|
||||||
keys:
|
|
||||||
- v1-dependencies-{{ checksum "package.json" }}
|
|
||||||
- v1-dependencies-
|
|
||||||
|
|
||||||
- run:
|
|
||||||
name: Install
|
|
||||||
command: yarn
|
|
||||||
|
|
||||||
- save_cache:
|
|
||||||
paths:
|
|
||||||
- node_modules
|
|
||||||
key: v1-dependencies-{{ checksum "package.json" }}
|
|
||||||
|
|
||||||
- run:
|
|
||||||
name: Build
|
|
||||||
command: yarn build-datatable
|
|
||||||
|
|
||||||
- run:
|
|
||||||
name: Copy README and LICENSE
|
|
||||||
command: |
|
|
||||||
cp LICENSE dist/ng-datatable/
|
|
||||||
cp README.md dist/ng-datatable/
|
|
||||||
|
|
||||||
- store_artifacts:
|
|
||||||
path: dist/ng-datatable
|
|
||||||
|
|
||||||
- deploy:
|
|
||||||
command: |
|
|
||||||
echo "${CIRCLE_BRANCH}"
|
|
||||||
if [ "${CIRCLE_BRANCH}" == "production" ]; then
|
|
||||||
yarn ci-publish
|
|
||||||
else
|
|
||||||
echo "Only the production branch is published"
|
|
||||||
fi
|
|
@ -4,7 +4,7 @@ root = true
|
|||||||
[*]
|
[*]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 4
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
41
.github/workflows/build.yaml
vendored
Normal file
41
.github/workflows/build.yaml
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
name: Build
|
||||||
|
run-name: Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build NPM Project
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: node:8
|
||||||
|
steps:
|
||||||
|
- name: Clone Repository
|
||||||
|
uses: ztimson/actions/clone@develop
|
||||||
|
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: npm i
|
||||||
|
|
||||||
|
- name: Build Project
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
- name: Upload to Registry
|
||||||
|
uses: ztimson/actions/npm/publish@develop
|
||||||
|
|
||||||
|
tag:
|
||||||
|
name: Tag Version
|
||||||
|
needs: build
|
||||||
|
if: ${{github.ref_name}} == develop
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: node:8
|
||||||
|
steps:
|
||||||
|
- name: Clone Repository
|
||||||
|
uses: ztimson/actions/clone@develop
|
||||||
|
|
||||||
|
- name: Get Version Number
|
||||||
|
run: echo "VERSION=$(cat package.json | grep version | grep -Eo ':.+' | grep -Eo '[[:alnum:]\.\/\-]+')" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Tag Version
|
||||||
|
uses: ztimson/actions/tag@develop
|
||||||
|
with:
|
||||||
|
tag: ${{env.VERSION}}
|
108
README.md
108
README.md
@ -1,8 +1,52 @@
|
|||||||
# ng-datatable
|
<!-- Header -->
|
||||||
|
<div id="top" align="center">
|
||||||
|
<br />
|
||||||
|
|
||||||
[![CircleCI](https://circleci.com/gh/ztimson/ng-datatable/tree/master.svg?style=svg)](https://circleci.com/gh/ztimson/ng-datatable/tree/master)
|
<!-- Logo -->
|
||||||
|
<img src="https://git.zakscode.com/repo-avatars/56e7adede041749f5df1d8b88b334e8c4cac38d7a4a574ccb42a624c52a35624" alt="Logo" width="200" height="200">
|
||||||
|
|
||||||
|
<!-- Title -->
|
||||||
|
### ng-datatable
|
||||||
|
|
||||||
|
<!-- Description -->
|
||||||
|
**Deprecated:** Angular Table Building Library
|
||||||
|
|
||||||
|
<!-- Repo badges -->
|
||||||
|
[![Version](https://img.shields.io/badge/dynamic/json.svg?label=Version&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/ng-datatable/tags&query=$[0].name)](https://git.zakscode.com/ztimson/ng-datatable/tags)
|
||||||
|
[![Pull Requests](https://img.shields.io/badge/dynamic/json.svg?label=Pull%20Requests&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/ng-datatable&query=open_pr_counter)](https://git.zakscode.com/ztimson/ng-datatable/pulls)
|
||||||
|
[![Issues](https://img.shields.io/badge/dynamic/json.svg?label=Issues&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/ng-datatable&query=open_issues_count)](https://git.zakscode.com/ztimson/ng-datatable/issues)
|
||||||
|
|
||||||
|
<!-- Links -->
|
||||||
|
|
||||||
|
---
|
||||||
|
<div>
|
||||||
|
<a href="https://git.zakscode.com/ztimson/ng-datatable/releases" target="_blank">Release Notes</a>
|
||||||
|
• <a href="https://git.zakscode.com/ztimson/ng-datatable/issues/new?template=.github%2fissue_template%2fbug.md" target="_blank">Report a Bug</a>
|
||||||
|
• <a href="https://git.zakscode.com/ztimson/ng-datatable/issues/new?template=.github%2fissue_template%2fenhancement.md" target="_blank">Request a Feature</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
---
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
- [ng-datatable](#top)
|
||||||
|
- [About](#about)
|
||||||
|
- [Built With](#built-with)
|
||||||
|
- [Setup](#setup)
|
||||||
|
- [Production](#production)
|
||||||
|
- [Development](#development)
|
||||||
|
- [Documentation](#documentation)
|
||||||
|
- [NgDatatableComponent](#ngdatatablecomponent)
|
||||||
|
- [Column](#column)
|
||||||
|
- [License](#license)
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
**Deprecated**
|
||||||
|
|
||||||
|
|
||||||
|
A lightweight, feature rich table to display data. It is built with twitter bootstrap in mind so it will be automatically styled if you have the css included but its simple table structure makes it easy to style.
|
||||||
|
|
||||||
A lightweight, feature rich table to display data. It is built with twitter bootstrap in mind but its simple table structor makes it easy to style.
|
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
@ -16,15 +60,27 @@ Features:
|
|||||||
- Mobile column hiding
|
- Mobile column hiding
|
||||||
- Checkboxes
|
- Checkboxes
|
||||||
|
|
||||||
|
|
||||||
[View on NPM](https://www.npmjs.com/package/@ztimson/ng-datatable)
|
[View on NPM](https://www.npmjs.com/package/@ztimson/ng-datatable)
|
||||||
|
|
||||||
[View the demo here](https://stackblitz.com/edit/angular-rzq6xm)
|
### Built With
|
||||||
|
[![Angular](https://img.shields.io/badge/Angular-DD0031?style=for-the-badge&logo=angular)](https://angular.io/)
|
||||||
|
[![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white)](https://typescriptlang.org/)
|
||||||
|
|
||||||
## Installing
|
## Setup
|
||||||
|
|
||||||
1. Install package `npm install @ztimson/ng-datatable --save`
|
<details>
|
||||||
2. Import into module
|
<summary>
|
||||||
|
<h3 id="production" style="display: inline">
|
||||||
|
Production
|
||||||
|
</h3>
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
#### Prerequisites
|
||||||
|
- [Node.js](https://nodejs.org/en/download)
|
||||||
|
|
||||||
|
#### Instructions
|
||||||
|
1. Install package `npm install @ztimson/ng-datatable --save`
|
||||||
|
2. Import into module
|
||||||
|
|
||||||
```Typescript
|
```Typescript
|
||||||
import {NgDatatableModule} from '@ztimsonm/ng-datatable'
|
import {NgDatatableModule} from '@ztimsonm/ng-datatable'
|
||||||
@ -39,13 +95,31 @@ import {NgDatatableModule} from '@ztimsonm/ng-datatable'
|
|||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Add to template
|
3. Add to template
|
||||||
|
|
||||||
```HTML
|
```HTML
|
||||||
<ng-datatable [columns]="columns" [data]="data"></ng-datatable>
|
<ng-datatable [columns]="columns" [data]="data"></ng-datatable>
|
||||||
```
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
## API
|
<details>
|
||||||
|
<summary>
|
||||||
|
<h3 id="development" style="display: inline">
|
||||||
|
Development
|
||||||
|
</h3>
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
#### Prerequisites
|
||||||
|
- [Node.js](https://nodejs.org/en/download)
|
||||||
|
|
||||||
|
#### Instructions
|
||||||
|
1. Install the dependencies: `npm install`
|
||||||
|
2. Start the Angular server: `npm run start`
|
||||||
|
3. Open [http://localhost:4200](http://localhost:4200)
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
### NgDatatableComponent
|
### NgDatatableComponent
|
||||||
|
|
||||||
@ -64,12 +138,14 @@ Selector: `ng-datatable`
|
|||||||
| @Input() pageLength: number | Number of rows per page. Default 20 |
|
| @Input() pageLength: number | Number of rows per page. Default 20 |
|
||||||
| @Input() page: number | Current page |
|
| @Input() page: number | Current page |
|
||||||
| @Input() paginate: boolean | Paginate rows or display all at once. Default true |
|
| @Input() paginate: boolean | Paginate rows or display all at once. Default true |
|
||||||
| @Input() paginateCssClass: string | Class added to the paginator
|
| @Input() paginateCssClass: string | Class added to the paginator |
|
||||||
| @Input() selectionMode: null/'single'/'multi' | Allow selecting none, single or multiple rows at once |
|
| @Input() selectionMode: null/'single'/'multi' | Allow selecting none, single or multiple rows at once |
|
||||||
| @Input() showCheckbox: boolean | Show checkbox' for mass selecting |
|
| @Input() showCheckbox: boolean | Show checkbox' for mass selecting |
|
||||||
| @Input() tableLayout: 'auto'/'fixed' | CSS table layout. Defaults to 'auto' |
|
| @Input() tableLayout: 'auto'/'fixed' | CSS table layout. Defaults to 'auto' |
|
||||||
| @Output() filterChanged: EventEmitter<(a, b) => 1/0/-1[]> | Applied filters |
|
| @Output() filterChanged: EventEmitter<(a, b) => 1/0/-1[]> | Applied filters |
|
||||||
|
| @Output() finished: EventEmitter<any[]> | Emits when finished processing data |
|
||||||
| @Output() pageChanged: EventEmitter<number> | New page |
|
| @Output() pageChanged: EventEmitter<number> | New page |
|
||||||
|
| @Output() processing: EventEmitter<any[]> | Emits when processing begins |
|
||||||
| @Output() selectionChanged: EventEmitter<any[]> | Selected rows |
|
| @Output() selectionChanged: EventEmitter<any[]> | Selected rows |
|
||||||
| pagedData: any[] | Array of rows on current page after sorting and filtering |
|
| pagedData: any[] | Array of rows on current page after sorting and filtering |
|
||||||
| processedData: any[] | Array of remaining rows after sorting and filtering |
|
| processedData: any[] | Array of remaining rows after sorting and filtering |
|
||||||
@ -105,6 +181,10 @@ Clear filters being applied to. Update can be set to false to prevent instant fi
|
|||||||
|
|
||||||
Clear all selected rows.
|
Clear all selected rows.
|
||||||
|
|
||||||
|
#### refresh()
|
||||||
|
|
||||||
|
Refreshes the grid
|
||||||
|
|
||||||
##### selectAll()
|
##### selectAll()
|
||||||
|
|
||||||
Select all rows. Ignores pagination but not filtering.
|
Select all rows. Ignores pagination but not filtering.
|
||||||
@ -144,3 +224,9 @@ Exported As: `Column`
|
|||||||
| sortFn: (a, b) => 1/0/-1 | Custom function to sort rows by |
|
| sortFn: (a, b) => 1/0/-1 | Custom function to sort rows by |
|
||||||
| template: TemplateRef<any> | Template to render row with |
|
| template: TemplateRef<any> | Template to render row with |
|
||||||
| width: number/string | CSS width property |
|
| width: number/string | CSS width property |
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
Copyright © 2023 Zakary Timson | Available under the Apache 2.0 License
|
||||||
|
|
||||||
|
See the [license](./LICENSE) for more information.
|
||||||
|
82
angular.json
82
angular.json
@ -17,9 +17,8 @@
|
|||||||
"index": "src/index.html",
|
"index": "src/index.html",
|
||||||
"main": "src/main.ts",
|
"main": "src/main.ts",
|
||||||
"polyfills": "src/polyfills.ts",
|
"polyfills": "src/polyfills.ts",
|
||||||
"tsConfig": "src/tsconfig.app.json",
|
"tsConfig": "tsconfig.json",
|
||||||
"assets": [
|
"assets": [
|
||||||
"src/favicon.ico",
|
|
||||||
"src/assets"
|
"src/assets"
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
@ -57,63 +56,6 @@
|
|||||||
"browserTarget": "Sandbox:build:production"
|
"browserTarget": "Sandbox:build:production"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"extract-i18n": {
|
|
||||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
|
||||||
"options": {
|
|
||||||
"browserTarget": "Sandbox:build"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"test": {
|
|
||||||
"builder": "@angular-devkit/build-angular:karma",
|
|
||||||
"options": {
|
|
||||||
"main": "src/test.ts",
|
|
||||||
"polyfills": "src/polyfills.ts",
|
|
||||||
"tsConfig": "src/tsconfig.spec.json",
|
|
||||||
"karmaConfig": "src/karma.conf.js",
|
|
||||||
"styles": [
|
|
||||||
"styles.css"
|
|
||||||
],
|
|
||||||
"scripts": [],
|
|
||||||
"assets": [
|
|
||||||
"src/favicon.ico",
|
|
||||||
"src/assets"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"builder": "@angular-devkit/build-angular:tslint",
|
|
||||||
"options": {
|
|
||||||
"tsConfig": [
|
|
||||||
"src/tsconfig.app.json",
|
|
||||||
"src/tsconfig.spec.json"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"**/node_modules/**"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Sandbox-e2e": {
|
|
||||||
"root": "e2e/",
|
|
||||||
"projectType": "application",
|
|
||||||
"architect": {
|
|
||||||
"e2e": {
|
|
||||||
"builder": "@angular-devkit/build-angular:protractor",
|
|
||||||
"options": {
|
|
||||||
"protractorConfig": "e2e/protractor.conf.js",
|
|
||||||
"devServerTarget": "Sandbox:serve"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"builder": "@angular-devkit/build-angular:tslint",
|
|
||||||
"options": {
|
|
||||||
"tsConfig": "e2e/tsconfig.e2e.json",
|
|
||||||
"exclude": [
|
|
||||||
"**/node_modules/**"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -134,29 +76,9 @@
|
|||||||
"project": "projects/ng-datatable/ng-package.prod.json"
|
"project": "projects/ng-datatable/ng-package.prod.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"test": {
|
|
||||||
"builder": "@angular-devkit/build-angular:karma",
|
|
||||||
"options": {
|
|
||||||
"main": "projects/ng-datatable/src/test.ts",
|
|
||||||
"tsConfig": "projects/ng-datatable/tsconfig.spec.json",
|
|
||||||
"karmaConfig": "projects/ng-datatable/karma.conf.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"builder": "@angular-devkit/build-angular:tslint",
|
|
||||||
"options": {
|
|
||||||
"tsConfig": [
|
|
||||||
"projects/ng-datatable/tsconfig.lib.json",
|
|
||||||
"projects/ng-datatable/tsconfig.spec.json"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"**/node_modules/**"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"defaultProject": "Sandbox"
|
"defaultProject": "Sandbox"
|
||||||
}
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
// Protractor configuration file, see link for more information
|
|
||||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
|
||||||
|
|
||||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
|
||||||
|
|
||||||
exports.config = {
|
|
||||||
allScriptsTimeout: 11000,
|
|
||||||
specs: [
|
|
||||||
'./src/**/*.e2e-spec.ts'
|
|
||||||
],
|
|
||||||
capabilities: {
|
|
||||||
'browserName': 'chrome'
|
|
||||||
},
|
|
||||||
directConnect: true,
|
|
||||||
baseUrl: 'http://localhost:4200/',
|
|
||||||
framework: 'jasmine',
|
|
||||||
jasmineNodeOpts: {
|
|
||||||
showColors: true,
|
|
||||||
defaultTimeoutInterval: 30000,
|
|
||||||
print: function() {}
|
|
||||||
},
|
|
||||||
onPrepare() {
|
|
||||||
require('ts-node').register({
|
|
||||||
project: require('path').join(__dirname, './tsconfig.e2e.json')
|
|
||||||
});
|
|
||||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,14 +0,0 @@
|
|||||||
import { AppPage } from './app.po';
|
|
||||||
|
|
||||||
describe('workspace-project App', () => {
|
|
||||||
let page: AppPage;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
page = new AppPage();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should display welcome message', () => {
|
|
||||||
page.navigateTo();
|
|
||||||
expect(page.getParagraphText()).toEqual('Welcome to app!');
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,11 +0,0 @@
|
|||||||
import { browser, by, element } from 'protractor';
|
|
||||||
|
|
||||||
export class AppPage {
|
|
||||||
navigateTo() {
|
|
||||||
return browser.get('/');
|
|
||||||
}
|
|
||||||
|
|
||||||
getParagraphText() {
|
|
||||||
return element(by.css('app-root h1')).getText();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "../out-tsc/app",
|
|
||||||
"module": "commonjs",
|
|
||||||
"target": "es5",
|
|
||||||
"types": [
|
|
||||||
"jasmine",
|
|
||||||
"jasminewd2",
|
|
||||||
"node"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
104
package.json
104
package.json
@ -1,55 +1,49 @@
|
|||||||
{
|
{
|
||||||
"name": "sandbox",
|
"name": "ng-datatable",
|
||||||
"version": "0.0.0",
|
"version": "1.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"start": "ng serve",
|
"start": "ng serve",
|
||||||
"build": "ng build",
|
"build": "ng build ng-datatable --prod"
|
||||||
"build-datatable": "ng build ng-datatable --prod",
|
},
|
||||||
"ci-publish": "cd dist/ng-datatable && ci-publish",
|
"dependencies": {
|
||||||
"test": "ng test",
|
"@angular/animations": "^6.0.0",
|
||||||
"lint": "ng lint",
|
"@angular/common": "^6.0.0",
|
||||||
"e2e": "ng e2e"
|
"@angular/compiler": "^6.0.0",
|
||||||
},
|
"@angular/core": "^6.0.0",
|
||||||
"private": true,
|
"@angular/forms": "^6.0.0",
|
||||||
"dependencies": {
|
"@angular/http": "^6.0.0",
|
||||||
"@angular/animations": "^6.0.0",
|
"@angular/platform-browser": "^6.0.0",
|
||||||
"@angular/common": "^6.0.0",
|
"@angular/platform-browser-dynamic": "^6.0.0",
|
||||||
"@angular/compiler": "^6.0.0",
|
"@angular/router": "^6.0.0",
|
||||||
"@angular/core": "^6.0.0",
|
"ci-publish": "^1.3.1",
|
||||||
"@angular/forms": "^6.0.0",
|
"core-js": "^2.5.4",
|
||||||
"@angular/http": "^6.0.0",
|
"rxjs": "^6.0.0",
|
||||||
"@angular/platform-browser": "^6.0.0",
|
"zone.js": "^0.8.26"
|
||||||
"@angular/platform-browser-dynamic": "^6.0.0",
|
},
|
||||||
"@angular/router": "^6.0.0",
|
"devDependencies": {
|
||||||
"ci-publish": "^1.3.1",
|
"@angular-devkit/build-angular": "~0.6.0",
|
||||||
"core-js": "^2.5.4",
|
"@angular-devkit/build-ng-packagr": "~0.6.8",
|
||||||
"rxjs": "^6.0.0",
|
"@angular/cli": "~6.0.0",
|
||||||
"zone.js": "^0.8.26"
|
"@angular/compiler-cli": "^6.0.0",
|
||||||
},
|
"@angular/language-service": "^6.0.0",
|
||||||
"devDependencies": {
|
"@types/jasmine": "~2.8.6",
|
||||||
"@angular-devkit/build-angular": "~0.6.0",
|
"@types/jasminewd2": "~2.0.3",
|
||||||
"@angular-devkit/build-ng-packagr": "~0.6.8",
|
"@types/node": "~8.9.4",
|
||||||
"@angular/cli": "~6.0.0",
|
"codelyzer": "~4.2.1",
|
||||||
"@angular/compiler-cli": "^6.0.0",
|
"jasmine-core": "~2.99.1",
|
||||||
"@angular/language-service": "^6.0.0",
|
"jasmine-spec-reporter": "~4.2.1",
|
||||||
"@types/jasmine": "~2.8.6",
|
"karma": "~1.7.1",
|
||||||
"@types/jasminewd2": "~2.0.3",
|
"karma-chrome-launcher": "~2.2.0",
|
||||||
"@types/node": "~8.9.4",
|
"karma-coverage-istanbul-reporter": "~1.4.2",
|
||||||
"codelyzer": "~4.2.1",
|
"karma-jasmine": "~1.1.1",
|
||||||
"jasmine-core": "~2.99.1",
|
"karma-jasmine-html-reporter": "^0.2.2",
|
||||||
"jasmine-spec-reporter": "~4.2.1",
|
"ng-packagr": "^3.0.0-rc.2",
|
||||||
"karma": "~1.7.1",
|
"protractor": "~5.3.0",
|
||||||
"karma-chrome-launcher": "~2.2.0",
|
"ts-node": "~5.0.1",
|
||||||
"karma-coverage-istanbul-reporter": "~1.4.2",
|
"tsickle": ">=0.25.5",
|
||||||
"karma-jasmine": "~1.1.1",
|
"tslib": "^1.7.1",
|
||||||
"karma-jasmine-html-reporter": "^0.2.2",
|
"tslint": "~5.9.1",
|
||||||
"ng-packagr": "^3.0.0-rc.2",
|
"typescript": "~2.7.2"
|
||||||
"protractor": "~5.3.0",
|
}
|
||||||
"ts-node": "~5.0.1",
|
}
|
||||||
"tsickle": ">=0.25.5",
|
|
||||||
"tslib": "^1.7.1",
|
|
||||||
"tslint": "~5.9.1",
|
|
||||||
"typescript": "~2.7.2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ztimson/ng-datatable",
|
"name": "@ztimson/ng-datatable",
|
||||||
"version": "1.5.2",
|
"version": "1.11.7",
|
||||||
"homepage": "https://github.com/ztimson/ng-datatable",
|
"homepage": "https://github.com/ztimson/ng-datatable",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"author": {
|
"author": {
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import {TemplateRef} from "@angular/core";
|
import {TemplateRef} from "@angular/core";
|
||||||
|
|
||||||
export interface Column {
|
export interface Column {
|
||||||
|
aggregate?: (rows: any[]) => any;
|
||||||
cssClass?: string; // CSS to add to column
|
cssClass?: string; // CSS to add to column
|
||||||
|
canSelect?: boolean;
|
||||||
hide?: boolean; // Hide column
|
hide?: boolean; // Hide column
|
||||||
hideMobile?: boolean; // Hide column on mobile
|
hideMobile?: boolean; // Hide column on mobile
|
||||||
initialSort?: 'asc' | 'desc'; // Sort this column initially
|
initialSort?: 'asc' | 'desc'; // Sort this column initially
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<table [class]="cssClass" [style.table-layout]="tableLayout">
|
<table [class]="cssClass + ' ngdt'" [style.table-layout]="tableLayout">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col *ngIf="showCheckbox && selectionMode !== null" width="30px">
|
<col *ngIf="showCheckbox && selectionMode !== null" width="30px">
|
||||||
<col *ngIf="expandedTemplate" width="30px">
|
<col *ngIf="expandedTemplate" width="30px">
|
||||||
@ -6,15 +6,15 @@
|
|||||||
<col *ngIf="c.hide !== true && !(c.hideMobile === true && width < mobileBreakpoint)" span="1" [width]="_convertWidth(c.width)">
|
<col *ngIf="c.hide !== true && !(c.hideMobile === true && width < mobileBreakpoint)" span="1" [width]="_convertWidth(c.width)">
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<thead>
|
<thead class="ngdt-header">
|
||||||
<tr>
|
<tr>
|
||||||
<th *ngIf="showCheckbox && selectionMode !== null">
|
<th *ngIf="showCheckbox && selectionMode !== null" class="ngdt-checkall">
|
||||||
<input *ngIf="selectionMode == 'multi'" type="checkbox" [checked]="processedData.length == selectedRows.size"
|
<input *ngIf="selectionMode == 'multi'" type="checkbox" [checked]="processedData.length == selectedRows.size"
|
||||||
(change)="$event.target.checked ? selectAll() : clearSelected()"/>
|
(change)="$event.target.checked ? selectAll() : clearSelected()"/>
|
||||||
</th>
|
</th>
|
||||||
<th *ngIf="expandedTemplate"></th>
|
<th *ngIf="expandedTemplate"></th>
|
||||||
<ng-container *ngFor="let c of columns; let i = index">
|
<ng-container *ngFor="let c of columns; let i = index">
|
||||||
<th *ngIf="c.hide !== true && !(c.hideMobile === true && width < mobileBreakpoint)" [class]="c.cssClass"
|
<th *ngIf="c.hide !== true && !(c.hideMobile === true && width < mobileBreakpoint)" [class]="c.cssClass + ' ngdt-column'"
|
||||||
style="cursor: pointer" (click)="sort(i)">
|
style="cursor: pointer" (click)="sort(i)">
|
||||||
<span *ngIf="sortedColumn == i && !sortedDesc">↑</span>
|
<span *ngIf="sortedColumn == i && !sortedDesc">↑</span>
|
||||||
<span *ngIf="sortedColumn == i && sortedDesc">↓</span>
|
<span *ngIf="sortedColumn == i && sortedDesc">↓</span>
|
||||||
@ -23,35 +23,54 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody class="ngdt-body">
|
||||||
<ng-container *ngFor="let row of pagedData; let i = index">
|
<ng-container *ngFor="let row of pagedData; let i = index">
|
||||||
<tr [ngClass]="{'active': selectedRows.has(i)}" (click)="updateSelected(i)">
|
<tr class="ngdt-row" [ngClass]="{'active': selectedRows.has(i)}">
|
||||||
<td *ngIf="showCheckbox && selectionMode !== null"><input type="checkbox" [checked]="selectedRows.has(i)"/></td>
|
<td *ngIf="showCheckbox && selectionMode !== null" class="ngdt-checkbox" (click)="updateSelected(i)">
|
||||||
<td *ngIf="expandedTemplate">
|
<input type="checkbox" [checked]="selectedRows.has(i)"/>
|
||||||
<span *ngIf="!selectedRows.has(i)">◢</span>
|
</td>
|
||||||
|
<td *ngIf="expandedTemplate" class="ngdt-expand" (click)="updateSelected(i)">
|
||||||
|
<span *ngIf="!selectedRows.has(i)">►</span>
|
||||||
<span *ngIf="selectedRows.has(i)">▼</span>
|
<span *ngIf="selectedRows.has(i)">▼</span>
|
||||||
</td>
|
</td>
|
||||||
<ng-container *ngFor="let c of columns">
|
<ng-container *ngFor="let c of columns">
|
||||||
<td *ngIf="c.hide !== true && !(c.hideMobile === true && width < mobileBreakpoint)">
|
<td *ngIf="c.hide !== true && !(c.hideMobile === true && width < mobileBreakpoint)" class="ngdt-cell" (click)="updateSelected(i, c)">
|
||||||
<ng-template #defaultTemplate let-value="value">{{value}}</ng-template>
|
<ng-template #defaultTemplate let-value="value">{{value}}</ng-template>
|
||||||
<ng-template [ngTemplateOutlet]="c.template || defaultTemplate"
|
<ng-template [ngTemplateOutlet]="c.template || defaultTemplate"
|
||||||
[ngTemplateOutletContext]="{object: row, value: _dotNotation(row, c.property)}">
|
[ngTemplateOutletContext]="{object: row, key: c.property, value: _dotNotation(row, c.property)}">
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</tr>
|
</tr>
|
||||||
<tr *ngIf="expandedTemplate && selectedRows.has(i)">
|
<tr *ngIf="expandedTemplate && selectedRows.has(i)" class="ngdt-detail">
|
||||||
<td [attr.colspan]="columns.length + (showCheckbox ? 1 : 0) + (expandedTemplate ? 1 : 0)">
|
<td [attr.colspan]="columns.length + (showCheckbox ? 1 : 0) + (expandedTemplate ? 1 : 0)">
|
||||||
<ng-template [ngTemplateOutlet]="expandedTemplate" [ngTemplateOutletContext]="{object: row}"></ng-template>
|
<ng-template [ngTemplateOutlet]="expandedTemplate" [ngTemplateOutletContext]="{object: row}"></ng-template>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
<tr class="ngdt-total">
|
||||||
|
<td *ngIf="showCheckbox && selectionMode !== null" class="ngdt-checkbox"></td>
|
||||||
|
<td *ngIf="expandedTemplate" class="ngdt-expand"></td>
|
||||||
|
<ng-container *ngFor="let c of columns">
|
||||||
|
<td class="ngdt-cell">{{aggregate(c)}}</td>
|
||||||
|
</ng-container>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<nav *ngIf="paginate" [class]="paginateCssClass" aria-label="Page navigation">
|
<nav *ngIf="paginate" [class]="paginateCssClass + 'ngdt-paginator'" aria-label="Page navigation">
|
||||||
<ul class="pagination">
|
<ul class="pagination">
|
||||||
<li class="page-item" [ngClass]="{'disabled': page <= 1}" (click)="changePage(page - 1)"><a class="page-link">Previous</a></li>
|
<li class="page-item ngdt-first" [ngClass]="{'disabled': page <= 1}" (click)="changePage(1)"><a class="page-link">First</a></li>
|
||||||
<li *ngFor="let i of pages" class="page-item" [ngClass]="{'active': page == i}"><a class="page-link" (click)="changePage(i)">{{i}}</a></li>
|
<li class="page-item ngdt-next" [ngClass]="{'disabled': page <= 1}" (click)="changePage(page - 1)"><a class="page-link">Previous</a></li>
|
||||||
<li class="page-item" [ngClass]="{'disabled': page >= pages.length}" (click)="changePage(page + 1)"><a class="page-link">Next</a></li>
|
<ng-container *ngFor="let i of pages;">
|
||||||
|
<li *ngIf="i > page - 3 && i < page + 3" class="page-item ngdt-page" [ngClass]="{'active': page == i}">
|
||||||
|
<a class="page-link" (click)="changePage(i)">
|
||||||
|
<span *ngIf="i == page - 2 && i > 1">...</span>
|
||||||
|
{{i}}
|
||||||
|
<span *ngIf="i == page + 2 && i != pages.length">...</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ng-container>
|
||||||
|
<li class="page-item ngdt-previous" [ngClass]="{'disabled': page >= pages.length}" (click)="changePage(page + 1)"><a class="page-link">Next</a></li>
|
||||||
|
<li class="page-item ngdt-last" [ngClass]="{'disabled': page == pages.length}" (click)="changePage(pages.length)"><a class="page-link">Last</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -2,159 +2,179 @@ import {Component, EventEmitter, HostListener, Input, OnInit, Output, TemplateRe
|
|||||||
import {Column} from './column';
|
import {Column} from './column';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ng-datatable',
|
selector: 'ng-datatable',
|
||||||
templateUrl: 'ng-datatable.component.html'
|
templateUrl: 'ng-datatable.component.html',
|
||||||
|
styles: ['.ngdt-expand {font-family: sans-serif;}']
|
||||||
})
|
})
|
||||||
export class NgDatatableComponent implements OnInit {
|
export class NgDatatableComponent implements OnInit {
|
||||||
// Inputs ============================================================================================================
|
// Inputs ============================================================================================================
|
||||||
@Input() cssClass: string; // CSS class to add to table element
|
@Input() cssClass: string; // CSS class to add to table element
|
||||||
@Input() columns: Column[] = []; // Columns to display on table
|
@Input() columns: Column[] = []; // Columns to display on table
|
||||||
@Input() expandedTemplate: TemplateRef<any>; // Template to use when expanding columns
|
@Input() expandedTemplate: TemplateRef<any>; // Template to use when expanding columns
|
||||||
@Input() mobileBreakpoint: number = 768; // Hide mobile false columns when screen size is less than
|
@Input() mobileBreakpoint: number = 768; // Hide mobile false columns when screen size is less than
|
||||||
@Input() pageLength: number = 20; // Number of rows per page
|
@Input() pageLength: number = 20; // Number of rows per page
|
||||||
@Input() page: number = 1; // Current page number
|
@Input() page: number = 1; // Current page number
|
||||||
@Input() paginate: boolean = true; // Should we paginate results
|
@Input() paginate: boolean = true; // Should we paginate results
|
||||||
@Input() paginateCssClass: string; // CSS class to add to paginator
|
@Input() paginateCssClass: string; // CSS class to add to paginator
|
||||||
@Input() selectionMode: null | 'single' | 'multi'; // Allow selecting no/single/multiple rows
|
@Input() selectionMode: null | 'single' | 'multi'; // Allow selecting no/single/multiple rows
|
||||||
@Input() showCheckbox: boolean; // Selection checkboxes
|
@Input() showCheckbox: boolean; // Selection checkboxes
|
||||||
@Input() tableLayout: 'auto' | 'fixed' = 'auto'; // How column widths are decided
|
@Input() tableLayout: 'auto' | 'fixed' = 'auto'; // How column widths are decided
|
||||||
|
|
||||||
// Outputs ===========================================================================================================
|
// Outputs ===========================================================================================================
|
||||||
@Output() filterChanged = new EventEmitter<any[]>(); // Output when filters change
|
@Output() filterChanged = new EventEmitter<any[]>(); // Output when filters change
|
||||||
@Output() pageChanged = new EventEmitter<number>(); // Output when page is changed
|
@Output() finished = new EventEmitter<any[]>(); // Fired after processing is finished
|
||||||
@Output() selectionChanged = new EventEmitter<any[]>(); // Output when selected rows changes
|
@Output() pageChanged = new EventEmitter<number>(); // Output when page is changed
|
||||||
|
@Output() processing = new EventEmitter<any[]>(); // Fires when grid begins to process
|
||||||
|
@Output() selectionChanged = new EventEmitter<any[]>(); // Output when selected rows changes
|
||||||
|
|
||||||
// Properties ========================================================================================================
|
// Properties ========================================================================================================
|
||||||
filters: ((el?: any, i?: number, arr?: any[]) => boolean)[] = []; // Array of process functions to apply to data
|
filters: ((el?: any, i?: number, arr?: any[]) => boolean)[] = []; // Array of process functions to apply to data
|
||||||
pages: number[] = []; // Array of possible pages
|
pages: number[] = []; // Array of possible pages
|
||||||
pagedData: any[] = []; // The data for the current
|
pagedData: any[] = []; // The data for the current
|
||||||
processedData: any[]; // rows left after filtering
|
processedData: any[] = []; // rows left after filtering
|
||||||
selectedRows = new Set<number>(); // Keep track of selected rows
|
selectedRows = new Set<number>(); // Keep track of selected rows
|
||||||
sortedColumn: number; // Column currently being sorted
|
sortedColumn: number; // Column currently being sorted
|
||||||
sortedDesc = false; // Is the sorted column being sorted in ascending or descending order
|
sortedDesc = false; // Is the sorted column being sorted in ascending or descending order
|
||||||
width = window.innerWidth; // Width of the screen. Used for hiding mobile columns
|
width = window.innerWidth; // Width of the screen. Used for hiding mobile columns
|
||||||
|
|
||||||
// Fields ============================================================================================================
|
// Fields ============================================================================================================
|
||||||
get count(): number { return this.processedData.length; } // Number of rows after filtering
|
get count(): number {
|
||||||
private _data: any[] = []; // Original data entered into table
|
return this.processedData ? this.processedData.length : 0;
|
||||||
get data(): any[] { return this.processedData; } // Return the processed data
|
} // Number of rows after filtering
|
||||||
@Input() set data(data: any[]) {
|
private _data: any[] = []; // Original data entered into table
|
||||||
this._data = data;
|
get data(): any[] {
|
||||||
this._process();
|
return this.processedData;
|
||||||
}
|
} // Return the processed data
|
||||||
|
@Input() set data(data: any[]) {
|
||||||
// ===================================================================================================================
|
this._data = data;
|
||||||
constructor() { }
|
this.refresh();
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
// Look through columns for an initial sort
|
|
||||||
for(let i = 0; i < this.columns.length; i++) {
|
|
||||||
if(this.columns[i].initialSort) {
|
|
||||||
this.sort(i, (this.columns[i].initialSort == 'desc'));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helpers ===========================================================================================================
|
|
||||||
private _process() {
|
|
||||||
this.clearSelected();
|
|
||||||
this.processedData = this._data;
|
|
||||||
this.filters.forEach(f => this.processedData = this.processedData.filter(f));
|
|
||||||
if(this.sortedColumn != null) {
|
|
||||||
if (this.columns[this.sortedColumn].sortFn) {
|
|
||||||
this.processedData = this.processedData.sort(this.columns[this.sortedColumn].sortFn);
|
|
||||||
} else {
|
|
||||||
this.processedData = this.processedData.sort((a: any, b: any) => {
|
|
||||||
if (a[this.columns[this.sortedColumn].property] > b[this.columns[this.sortedColumn].property]) return 1;
|
|
||||||
if (a[this.columns[this.sortedColumn].property] < b[this.columns[this.sortedColumn].property]) return -1;
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (this.sortedDesc) this.processedData = this.processedData.reverse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.paginate) {
|
// ===================================================================================================================
|
||||||
this.pages = Array(Math.ceil(this.processedData.length / this.pageLength)).fill(0).map((ignore, i) => i + 1);
|
constructor() {
|
||||||
this.pagedData = this.processedData.filter((ignore, i) => i >= (this.page - 1) * this.pageLength && i < this.page * this.pageLength);
|
|
||||||
} else {
|
|
||||||
this.pagedData = this.processedData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_convertWidth(width) {
|
|
||||||
if(typeof width == 'number') return `${width}px`;
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
_dotNotation(obj: object, prop: string) {
|
|
||||||
return prop.split('.').reduce((obj, prop) => obj[prop], obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
addFilter(...filters: ((row?: any, index?: number, arr?: any[]) => boolean)[]) {
|
|
||||||
this.filters = this.filters.concat(filters);
|
|
||||||
this._process();
|
|
||||||
this.filterChanged.emit(this.filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
changePage(page: number) {
|
|
||||||
if(!this.paginate || page < 1 || page > this.pages.length) return;
|
|
||||||
this.page = page;
|
|
||||||
this._process();
|
|
||||||
this.pageChanged.emit(this.page);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearFilters(update=true) {
|
|
||||||
this.filters = [];
|
|
||||||
if(update) this._process();
|
|
||||||
this.filterChanged.emit(this.filters);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearSelected() {
|
|
||||||
let emit = this.selectedRows.size > 0;
|
|
||||||
this.selectedRows.clear();
|
|
||||||
if(emit) this.selectionChanged.emit([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@HostListener('window:resize', ['$event'])
|
|
||||||
onResize(event) { this.width = event.target.innerWidth; }
|
|
||||||
|
|
||||||
selectAll() {
|
|
||||||
this.processedData.forEach((ignore, i) => this.selectedRows.add(i));
|
|
||||||
this.selectionChanged.emit(this.processedData);
|
|
||||||
}
|
|
||||||
|
|
||||||
sort(columnIndex: number, desc?: boolean) {
|
|
||||||
let column = this.columns[columnIndex];
|
|
||||||
if (!column || column.sort === false) return; // If column is un-sortable return
|
|
||||||
|
|
||||||
// Figure out sorting direction if not supplied
|
|
||||||
if(desc === undefined) {
|
|
||||||
desc = false;
|
|
||||||
if(columnIndex == this.sortedColumn) desc = !this.sortedDesc;
|
|
||||||
}
|
|
||||||
this.sortedColumn = columnIndex;
|
|
||||||
this.sortedDesc = desc;
|
|
||||||
|
|
||||||
// Preform sort
|
|
||||||
this._process();
|
|
||||||
}
|
|
||||||
|
|
||||||
updateSelected(index: number) {
|
|
||||||
if (this.selectionMode == null) return;
|
|
||||||
|
|
||||||
if (this.selectionMode == 'single') {
|
|
||||||
let alreadySelected = this.selectedRows.has(index);
|
|
||||||
this.selectedRows.clear();
|
|
||||||
if(!alreadySelected) this.selectedRows.add(index);
|
|
||||||
} else {
|
|
||||||
if (this.selectedRows.has(index)) {
|
|
||||||
this.selectedRows.delete(index);
|
|
||||||
} else {
|
|
||||||
this.selectedRows.add(index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.selectionChanged.emit(this.processedData.filter((row, i) => this.selectedRows.has(i)));
|
ngOnInit() {
|
||||||
}
|
// Look through columns for an initial sort
|
||||||
|
for (let i = 0; i < this.columns.length; i++) {
|
||||||
|
if (this.columns[i].initialSort) {
|
||||||
|
this.sort(i, (this.columns[i].initialSort == 'desc'));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpers ===========================================================================================================
|
||||||
|
_convertWidth(width) {
|
||||||
|
if (typeof width == 'number') return `${width}px`;
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dotNotation(obj: object, prop: string) {
|
||||||
|
return prop.split('.').reduce((obj, prop) => obj[prop], obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
addFilter(...filters: ((row?: any, index?: number, arr?: any[]) => boolean)[]) {
|
||||||
|
this.filters = this.filters.concat(filters);
|
||||||
|
this.refresh();
|
||||||
|
this.filterChanged.emit(this.filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
aggregate(col: Column) {
|
||||||
|
if (!col.aggregate) return '';
|
||||||
|
return col.aggregate(this.processedData.map(row => this._dotNotation(row, col.property)));
|
||||||
|
}
|
||||||
|
|
||||||
|
changePage(page: number) {
|
||||||
|
if (!this.paginate || page < 1 || page > this.pages.length) return;
|
||||||
|
this.page = page;
|
||||||
|
this.refresh();
|
||||||
|
this.pageChanged.emit(this.page);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearFilters(update = true) {
|
||||||
|
this.filters = [];
|
||||||
|
if (update) this.refresh();
|
||||||
|
this.filterChanged.emit(this.filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSelected() {
|
||||||
|
let emit = this.selectedRows.size > 0;
|
||||||
|
this.selectedRows.clear();
|
||||||
|
if (emit) this.selectionChanged.emit([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostListener('window:resize', ['$event'])
|
||||||
|
onResize(event) {
|
||||||
|
this.width = event.target.innerWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
this.processing.emit(this.processedData);
|
||||||
|
this.clearSelected();
|
||||||
|
this.processedData = this._data;
|
||||||
|
this.filters.forEach(f => this.processedData = this.processedData.filter(f));
|
||||||
|
if (this.sortedColumn != null && this.processedData) {
|
||||||
|
if (this.columns[this.sortedColumn].sortFn) {
|
||||||
|
this.processedData = this.processedData.sort(this.columns[this.sortedColumn].sortFn);
|
||||||
|
} else {
|
||||||
|
this.processedData = this.processedData.sort((a: any, b: any) => {
|
||||||
|
if (this._dotNotation(a, this.columns[this.sortedColumn].property) > this._dotNotation(b, this.columns[this.sortedColumn].property)) return 1;
|
||||||
|
if (this._dotNotation(a, this.columns[this.sortedColumn].property) < this._dotNotation(b, this.columns[this.sortedColumn].property)) return -1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.sortedDesc) this.processedData = this.processedData.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.paginate && this.processedData) {
|
||||||
|
this.pages = Array(Math.ceil(this.processedData.length / this.pageLength)).fill(0).map((ignore, i) => i + 1);
|
||||||
|
if (!this.page) this.page = 1;
|
||||||
|
if (this.page > this.pages.length) this.page = this.pages.length;
|
||||||
|
this.pagedData = this.processedData.filter((ignore, i) => i >= (this.page - 1) * this.pageLength && i < this.page * this.pageLength);
|
||||||
|
} else {
|
||||||
|
this.pagedData = this.processedData;
|
||||||
|
}
|
||||||
|
this.finished.emit(this.processedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
selectAll() {
|
||||||
|
this.processedData.forEach((ignore, i) => this.selectedRows.add(i));
|
||||||
|
this.selectionChanged.emit(this.processedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
sort(columnIndex: number, desc?: boolean) {
|
||||||
|
let column = this.columns[columnIndex];
|
||||||
|
if (!column || column.sort === false) return; // If column is un-sortable return
|
||||||
|
|
||||||
|
// Figure out sorting direction if not supplied
|
||||||
|
if (desc === undefined) {
|
||||||
|
desc = false;
|
||||||
|
if (columnIndex == this.sortedColumn) desc = !this.sortedDesc;
|
||||||
|
}
|
||||||
|
this.sortedColumn = columnIndex;
|
||||||
|
this.sortedDesc = desc;
|
||||||
|
|
||||||
|
// Preform sort
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSelected(index: number, column?: Column) {
|
||||||
|
if (this.selectionMode == null) return;
|
||||||
|
if (column && column.canSelect === false) return;
|
||||||
|
|
||||||
|
if (this.selectionMode == 'single') {
|
||||||
|
let alreadySelected = this.selectedRows.has(index);
|
||||||
|
this.selectedRows.clear();
|
||||||
|
if (!alreadySelected) this.selectedRows.add(index);
|
||||||
|
} else {
|
||||||
|
if (this.selectedRows.has(index)) {
|
||||||
|
this.selectedRows.delete(index);
|
||||||
|
} else {
|
||||||
|
this.selectedRows.add(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectionChanged.emit(this.processedData.filter((row, i) => this.selectedRows.has(i)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,5 @@
|
|||||||
"strictInjectionParameters": true,
|
"strictInjectionParameters": true,
|
||||||
"flatModuleId": "AUTOGENERATED",
|
"flatModuleId": "AUTOGENERATED",
|
||||||
"flatModuleOutFile": "AUTOGENERATED"
|
"flatModuleOutFile": "AUTOGENERATED"
|
||||||
},
|
}
|
||||||
"exclude": [
|
|
||||||
"**/*.spec.ts"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
Table CSS
|
Table CSS
|
||||||
<input [(ngModel)]="tableCSS"> Selection Mode
|
<input [(ngModel)]="tableCSS"> Selection Mode
|
||||||
<select [(ngModel)]="selectionMode">
|
<select [(ngModel)]="selectionMode">
|
||||||
<option>None</option>
|
<option>None</option>
|
||||||
<option>single</option>
|
<option>single</option>
|
||||||
<option>multi</option>
|
<option>multi</option>
|
||||||
</select>
|
</select>
|
||||||
Checkbox
|
Checkbox
|
||||||
<input type="checkbox" [(ngModel)]="checkbox"> Expandable
|
<input type="checkbox" [(ngModel)]="checkbox"> Expandable
|
||||||
@ -13,13 +13,13 @@ Checkbox
|
|||||||
<input placeholder="Search" (keyup)="search.next($event.target.value)">
|
<input placeholder="Search" (keyup)="search.next($event.target.value)">
|
||||||
<br> Selected: {{table.selectedRows.size}}/{{table.processedData.length}}
|
<br> Selected: {{table.selectedRows.size}}/{{table.processedData.length}}
|
||||||
<ng-datatable #table [cssClass]="tableCSS" [columns]="columns" [data]="data" [expandedTemplate]="expandable ? expanded : null"
|
<ng-datatable #table [cssClass]="tableCSS" [columns]="columns" [data]="data" [expandedTemplate]="expandable ? expanded : null"
|
||||||
[showCheckbox]="checkbox" [paginate]="false" [selectionMode]="selectionMode == 'None' ? null : selectionMode" (rowSelected)="log($event)">
|
[showCheckbox]="checkbox" [paginate]="true" [selectionMode]="selectionMode == 'None' ? null : selectionMode" (rowSelected)="log($event)">
|
||||||
<ng-template #expanded let-object="object">
|
<ng-template #expanded let-object="object">
|
||||||
Hello {{object.firstName}} {{object.lastName}}, How are you today?
|
Hello {{object.firstName}} {{object.lastName}}, How are you today?
|
||||||
<span *ngIf="object.age < 18">I can see that you are under age.</span>
|
<span *ngIf="object.age < 18">I can see that you are under age.</span>
|
||||||
<span *ngIf="object.age > 84">I can see that you are over the average life expectancy.</span>
|
<span *ngIf="object.age > 84">I can see that you are over the average life expectancy.</span>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template #age let-value="value">
|
<ng-template #age let-value="value">
|
||||||
<strong [ngClass]="{'text-success': value < 18, 'text-danger': value > 84}">{{value}}</strong>
|
<strong [ngClass]="{'text-success': value < 18, 'text-danger': value > 84}">{{value}}</strong>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ng-datatable>
|
</ng-datatable>
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
import { TestBed, async } from '@angular/core/testing';
|
|
||||||
import { AppComponent } from './app.component';
|
|
||||||
describe('AppComponent', () => {
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [
|
|
||||||
AppComponent
|
|
||||||
],
|
|
||||||
}).compileComponents();
|
|
||||||
}));
|
|
||||||
it('should create the app', async(() => {
|
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
|
||||||
const app = fixture.debugElement.componentInstance;
|
|
||||||
expect(app).toBeTruthy();
|
|
||||||
}));
|
|
||||||
it(`should have as title 'app'`, async(() => {
|
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
|
||||||
const app = fixture.debugElement.componentInstance;
|
|
||||||
expect(app.title).toEqual('app');
|
|
||||||
}));
|
|
||||||
it('should render title in a h1 tag', async(() => {
|
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
|
||||||
fixture.detectChanges();
|
|
||||||
const compiled = fixture.debugElement.nativeElement;
|
|
||||||
expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!');
|
|
||||||
}));
|
|
||||||
});
|
|
File diff suppressed because one or more lines are too long
@ -1,20 +1,20 @@
|
|||||||
import { BrowserModule } from '@angular/platform-browser';
|
import {NgModule} from '@angular/core';
|
||||||
import { NgModule } from '@angular/core';
|
|
||||||
|
|
||||||
import { AppComponent } from './app.component';
|
|
||||||
import {FormsModule} from "@angular/forms";
|
import {FormsModule} from "@angular/forms";
|
||||||
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
import {NgDatatableModule} from "../../projects/ng-datatable/src/lib/ng-datatable.module";
|
import {NgDatatableModule} from "../../projects/ng-datatable/src/lib/ng-datatable.module";
|
||||||
|
|
||||||
|
import {AppComponent} from './app.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent
|
AppComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
NgDatatableModule
|
NgDatatableModule
|
||||||
],
|
],
|
||||||
providers: [],
|
providers: [],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule {}
|
||||||
|
@ -1,15 +1,3 @@
|
|||||||
// This file can be replaced during build by using the `fileReplacements` array.
|
|
||||||
// `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`.
|
|
||||||
// The list of file replacements can be found in `angular.json`.
|
|
||||||
|
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: false
|
production: false
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* In development mode, to ignore zone related error stack frames such as
|
|
||||||
* `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can
|
|
||||||
* import the following file, but please comment it out in production mode
|
|
||||||
* because it will have performance impact when throw error
|
|
||||||
*/
|
|
||||||
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
|
||||||
|
BIN
src/favicon.ico
BIN
src/favicon.ico
Binary file not shown.
Before Width: | Height: | Size: 5.3 KiB |
@ -1,31 +0,0 @@
|
|||||||
// Karma configuration file, see link for more information
|
|
||||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
|
||||||
|
|
||||||
module.exports = function (config) {
|
|
||||||
config.set({
|
|
||||||
basePath: '',
|
|
||||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
|
||||||
plugins: [
|
|
||||||
require('karma-jasmine'),
|
|
||||||
require('karma-chrome-launcher'),
|
|
||||||
require('karma-jasmine-html-reporter'),
|
|
||||||
require('karma-coverage-istanbul-reporter'),
|
|
||||||
require('@angular-devkit/build-angular/plugins/karma')
|
|
||||||
],
|
|
||||||
client: {
|
|
||||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
|
||||||
},
|
|
||||||
coverageIstanbulReporter: {
|
|
||||||
dir: require('path').join(__dirname, '../coverage'),
|
|
||||||
reports: ['html', 'lcovonly'],
|
|
||||||
fixWebpackSourcePaths: true
|
|
||||||
},
|
|
||||||
reporters: ['progress', 'kjhtml'],
|
|
||||||
port: 9876,
|
|
||||||
colors: true,
|
|
||||||
logLevel: config.LOG_INFO,
|
|
||||||
autoWatch: true,
|
|
||||||
browsers: ['Chrome'],
|
|
||||||
singleRun: false
|
|
||||||
});
|
|
||||||
};
|
|
20
src/test.ts
20
src/test.ts
@ -1,20 +0,0 @@
|
|||||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
|
||||||
|
|
||||||
import 'zone.js/dist/zone-testing';
|
|
||||||
import { getTestBed } from '@angular/core/testing';
|
|
||||||
import {
|
|
||||||
BrowserDynamicTestingModule,
|
|
||||||
platformBrowserDynamicTesting
|
|
||||||
} from '@angular/platform-browser-dynamic/testing';
|
|
||||||
|
|
||||||
declare const require: any;
|
|
||||||
|
|
||||||
// First, initialize the Angular testing environment.
|
|
||||||
getTestBed().initTestEnvironment(
|
|
||||||
BrowserDynamicTestingModule,
|
|
||||||
platformBrowserDynamicTesting()
|
|
||||||
);
|
|
||||||
// Then we find all the tests.
|
|
||||||
const context = require.context('./', true, /\.spec\.ts$/);
|
|
||||||
// And load the modules.
|
|
||||||
context.keys().map(context);
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "../out-tsc/app",
|
|
||||||
"module": "es2015",
|
|
||||||
"types": []
|
|
||||||
},
|
|
||||||
"exclude": [
|
|
||||||
"src/test.ts",
|
|
||||||
"**/*.spec.ts"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "../out-tsc/spec",
|
|
||||||
"module": "commonjs",
|
|
||||||
"types": [
|
|
||||||
"jasmine",
|
|
||||||
"node"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"test.ts",
|
|
||||||
"polyfills.ts"
|
|
||||||
],
|
|
||||||
"include": [
|
|
||||||
"**/*.spec.ts",
|
|
||||||
"**/*.d.ts"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../tslint.json",
|
|
||||||
"rules": {
|
|
||||||
"directive-selector": [
|
|
||||||
true,
|
|
||||||
"attribute",
|
|
||||||
"app",
|
|
||||||
"camelCase"
|
|
||||||
],
|
|
||||||
"component-selector": [
|
|
||||||
true,
|
|
||||||
"element",
|
|
||||||
"app",
|
|
||||||
"kebab-case"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +1,29 @@
|
|||||||
{
|
{
|
||||||
"compileOnSave": false,
|
"compileOnSave": false,
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
"outDir": "./dist/out-tsc",
|
"outDir": "../out-tsc/app",
|
||||||
"sourceMap": true,
|
"module": "es2015",
|
||||||
"declaration": false,
|
"sourceMap": true,
|
||||||
"moduleResolution": "node",
|
"declaration": false,
|
||||||
"emitDecoratorMetadata": true,
|
"moduleResolution": "node",
|
||||||
"experimentalDecorators": true,
|
"emitDecoratorMetadata": true,
|
||||||
"target": "es5",
|
"experimentalDecorators": true,
|
||||||
"typeRoots": [
|
"target": "es5",
|
||||||
"node_modules/@types"
|
"typeRoots": [
|
||||||
],
|
"node_modules/@types"
|
||||||
"lib": [
|
],
|
||||||
"es2017",
|
"lib": [
|
||||||
"dom"
|
"es2017",
|
||||||
],
|
"dom"
|
||||||
"paths": {
|
],
|
||||||
"ng-datatable": [
|
"paths": {
|
||||||
"dist/ng-datatable"
|
"ng-datatable": [
|
||||||
],
|
"dist/ng-datatable"
|
||||||
"ng-datatable/*": [
|
],
|
||||||
"dist/ng-datatable/*"
|
"ng-datatable/*": [
|
||||||
]
|
"dist/ng-datatable/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
130
tslint.json
130
tslint.json
@ -1,130 +0,0 @@
|
|||||||
{
|
|
||||||
"rulesDirectory": [
|
|
||||||
"node_modules/codelyzer"
|
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"arrow-return-shorthand": true,
|
|
||||||
"callable-types": true,
|
|
||||||
"class-name": true,
|
|
||||||
"comment-format": [
|
|
||||||
true,
|
|
||||||
"check-space"
|
|
||||||
],
|
|
||||||
"curly": true,
|
|
||||||
"deprecation": {
|
|
||||||
"severity": "warn"
|
|
||||||
},
|
|
||||||
"eofline": true,
|
|
||||||
"forin": true,
|
|
||||||
"import-blacklist": [
|
|
||||||
true,
|
|
||||||
"rxjs/Rx"
|
|
||||||
],
|
|
||||||
"import-spacing": true,
|
|
||||||
"indent": [
|
|
||||||
true,
|
|
||||||
"spaces"
|
|
||||||
],
|
|
||||||
"interface-over-type-literal": true,
|
|
||||||
"label-position": true,
|
|
||||||
"max-line-length": [
|
|
||||||
true,
|
|
||||||
140
|
|
||||||
],
|
|
||||||
"member-access": false,
|
|
||||||
"member-ordering": [
|
|
||||||
true,
|
|
||||||
{
|
|
||||||
"order": [
|
|
||||||
"static-field",
|
|
||||||
"instance-field",
|
|
||||||
"static-method",
|
|
||||||
"instance-method"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"no-arg": true,
|
|
||||||
"no-bitwise": true,
|
|
||||||
"no-console": [
|
|
||||||
true,
|
|
||||||
"debug",
|
|
||||||
"info",
|
|
||||||
"time",
|
|
||||||
"timeEnd",
|
|
||||||
"trace"
|
|
||||||
],
|
|
||||||
"no-construct": true,
|
|
||||||
"no-debugger": true,
|
|
||||||
"no-duplicate-super": true,
|
|
||||||
"no-empty": false,
|
|
||||||
"no-empty-interface": true,
|
|
||||||
"no-eval": true,
|
|
||||||
"no-inferrable-types": [
|
|
||||||
true,
|
|
||||||
"ignore-params"
|
|
||||||
],
|
|
||||||
"no-misused-new": true,
|
|
||||||
"no-non-null-assertion": true,
|
|
||||||
"no-shadowed-variable": true,
|
|
||||||
"no-string-literal": false,
|
|
||||||
"no-string-throw": true,
|
|
||||||
"no-switch-case-fall-through": true,
|
|
||||||
"no-trailing-whitespace": true,
|
|
||||||
"no-unnecessary-initializer": true,
|
|
||||||
"no-unused-expression": true,
|
|
||||||
"no-use-before-declare": true,
|
|
||||||
"no-var-keyword": true,
|
|
||||||
"object-literal-sort-keys": false,
|
|
||||||
"one-line": [
|
|
||||||
true,
|
|
||||||
"check-open-brace",
|
|
||||||
"check-catch",
|
|
||||||
"check-else",
|
|
||||||
"check-whitespace"
|
|
||||||
],
|
|
||||||
"prefer-const": true,
|
|
||||||
"quotemark": [
|
|
||||||
true,
|
|
||||||
"single"
|
|
||||||
],
|
|
||||||
"radix": true,
|
|
||||||
"semicolon": [
|
|
||||||
true,
|
|
||||||
"always"
|
|
||||||
],
|
|
||||||
"triple-equals": [
|
|
||||||
true,
|
|
||||||
"allow-null-check"
|
|
||||||
],
|
|
||||||
"typedef-whitespace": [
|
|
||||||
true,
|
|
||||||
{
|
|
||||||
"call-signature": "nospace",
|
|
||||||
"index-signature": "nospace",
|
|
||||||
"parameter": "nospace",
|
|
||||||
"property-declaration": "nospace",
|
|
||||||
"variable-declaration": "nospace"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"unified-signatures": true,
|
|
||||||
"variable-name": false,
|
|
||||||
"whitespace": [
|
|
||||||
true,
|
|
||||||
"check-branch",
|
|
||||||
"check-decl",
|
|
||||||
"check-operator",
|
|
||||||
"check-separator",
|
|
||||||
"check-type"
|
|
||||||
],
|
|
||||||
"no-output-on-prefix": true,
|
|
||||||
"use-input-property-decorator": true,
|
|
||||||
"use-output-property-decorator": true,
|
|
||||||
"use-host-property-decorator": true,
|
|
||||||
"no-input-rename": true,
|
|
||||||
"no-output-rename": true,
|
|
||||||
"use-life-cycle-interface": true,
|
|
||||||
"use-pipe-transform-interface": true,
|
|
||||||
"component-class-suffix": true,
|
|
||||||
"directive-class-suffix": true
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user