├── .angular-cli.json ├── .gitattributes ├── .gitignore ├── README.md ├── index.ts ├── package.json ├── src ├── demo │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ └── app.routes.ts │ ├── assets │ │ ├── .gitkeep │ │ └── data │ │ │ └── data.json │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── index.html │ ├── main.ts │ ├── pages │ │ ├── ng2-table-view-test │ │ │ ├── cols │ │ │ │ └── columns.ts │ │ │ ├── index.ts │ │ │ ├── page.html │ │ │ └── page.ts │ │ └── service │ │ │ └── data.service.ts │ ├── polyfills.ts │ ├── styles.css │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ ├── typings.d.ts │ └── utils │ │ └── app-utils.ts └── ng2-table-view │ ├── index.ts │ ├── ng2-table-view.ts │ ├── table-material.module.ts │ ├── table.view.module.ts │ └── table │ ├── config │ ├── ColumnIfc.ts │ ├── ConfigBuilder.ts │ ├── SelectTableColumn.ts │ ├── TableColumn.ts │ ├── TableColumns.ts │ └── TableView.ts │ ├── directive │ ├── filtering.ts │ ├── paging │ │ ├── pagination.html │ │ ├── paging.css │ │ └── paging.ts │ ├── sorting.ts │ └── table-cell-custom-template.ts │ ├── pipes │ ├── nested-table-data-pipe.ts │ └── table-data-pipe.ts │ ├── service │ └── emitter.service.ts │ ├── table.css │ ├── table.html │ ├── table.ts │ └── template │ └── select.html ├── tsconfig.json └── tslint.json /.angular-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "project": { 4 | "name": "NG2TableViewApp" 5 | }, 6 | "apps": [ 7 | { 8 | "root": "src", 9 | "outDir": "dist", 10 | "assets": [ 11 | "demo/assets", 12 | "favicon.ico" 13 | ], 14 | "index": "demo/index.html", 15 | "main": "demo/main.ts", 16 | "polyfills": "demo/polyfills.ts", 17 | "test": "demo/test.ts", 18 | "tsconfig": "demo/tsconfig.app.json", 19 | "testTsconfig": "demo/tsconfig.spec.json", 20 | "prefix": "appTest", 21 | "styles": [ 22 | "demo/styles.css" 23 | ], 24 | "scripts": [], 25 | "environmentSource": "demo/environments/environment.ts", 26 | "environments": { 27 | "dev": "demo/environments/environment.ts", 28 | "prod": "demo/environments/environment.prod.ts" 29 | } 30 | } 31 | ], 32 | "defaults": { 33 | "styleExt": "css", 34 | "class": { 35 | "spec": false 36 | }, 37 | "component": {} 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | dist/* 8 | 9 | # Recycle Bin used on file shares 10 | $RECYCLE.BIN/ 11 | 12 | # Windows Installer files 13 | *.cab 14 | *.msi 15 | *.msm 16 | *.msp 17 | 18 | # Windows shortcuts 19 | *.lnk 20 | 21 | # ========================= 22 | # Operating System Files 23 | # ========================= 24 | 25 | # OSX 26 | # ========================= 27 | 28 | .DS_Store 29 | .AppleDouble 30 | .LSOverride 31 | 32 | # Thumbnails 33 | ._* 34 | 35 | # Files that might appear in the root of a volume 36 | .DocumentRevisions-V100 37 | .fseventsd 38 | .Spotlight-V100 39 | .TemporaryItems 40 | .Trashes 41 | .VolumeIcon.icns 42 | 43 | # Directories potentially created on remote AFP share 44 | .AppleDB 45 | .AppleDesktop 46 | Network Trash Folder 47 | Temporary Items 48 | .apdisk 49 | node_modules 50 | typings -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NG2TableView [![npm version](https://badge.fury.io/js/NG2TableView.svg)](https://www.npmjs.com/package/NG2TableView) 2 | NG2TableView for Angular2 apps. 3 | 4 | Table component with sorting, filtering, paging, custom cell template, nested values bind ... for Angular2. inspired by [ng2-table](https://github.com/valor-software/ng2-table) 5 | 6 | 7 | # Usage & Demo 8 | 9 | [http://dennis-b.github.io/NG2TableView/](http://dennis-b.github.io/NG2TableView/) 10 | 11 | - - - 12 | 13 | ## Getting Started 14 | Make sure you have [Nodejs](https://nodejs.org/) 15 | 16 | 17 | Best way to install ***NG2TableView*** is through [npm](https://www.npmjs.com/package/NG2TableView) 18 | 19 | ```bash 20 | npm i NG2TableView --save 21 | ``` 22 | Or, you can [download it in a ZIP file](https://github.com/dennis-b/NG2TableView/archive/master.zip). 23 | 24 | 25 | ## Usage 26 | 27 | **import module in yours AppModule:** 28 | 29 | ``` 30 | import {Ng2TableViewModule} from "NG2TableView"; 31 | @NgModule({ 32 | imports: [Ng2TableViewModule, ...], 33 | ... 34 | }) 35 | export class AppModule { 36 | } 37 | 38 | ``` 39 | 40 | ## some-comp.ts 41 | ```bash 42 | import {TableView} from "NG2TableView"; 43 | import {Component, OnInit} from '@angular/core'; 44 | import {PageTableColumns} from "./cols/columns"; 45 | import {Route, ActivatedRoute} from "@angular/router"; 46 | 47 | @Component({ 48 | selector: "demo-page", 49 | template: require('./page.html') 50 | }) 51 | export class Page extends TableView implements OnInit { 52 | 53 | constructor(private route: ActivatedRoute) { 54 | super(route.data.getValue().users); 55 | } 56 | 57 | ngOnInit() { 58 | this.getBuilder() 59 | .addCols(PageTableColumns) 60 | .setPaging(true) 61 | .setItemsPerPage(5) 62 | .setSelectable(true); 63 | 64 | this.buildTable(); 65 | } 66 | } 67 | ``` 68 | 69 | ## columns.ts 70 | ```bash 71 | export const PageTableColumns:Array = new TableColumns() 72 | .addCol(new TableColumn() 73 | .setTitle("index") 74 | .setName("index") 75 | .setSort(true) 76 | ) 77 | .addCol(new TableColumn() 78 | .setTitle("Editable name ") 79 | .setName("name") 80 | .setTemplate(require("./custom-template.html")) 81 | .setSort(true) 82 | ) 83 | 84 | ... 85 | ``` 86 | 87 | ## page.html (template) 88 | 89 | ```bash 90 |
91 | 92 |
93 | 99 | 100 |
101 | 102 | 106 | 107 | 108 |
109 | 112 | 113 |
114 |
115 |
116 | 117 | ``` 118 | 119 | ... 120 | 121 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Dennis on 17/05/2016. 3 | */ 4 | export * from './src/ng2-table-view'; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NG2TableView", 3 | "version": "1.5.1", 4 | "description": "Table View for angular 2", 5 | "author": "Dennis Borshchevski ", 6 | "homepage": "https://github.com/dennis-b/NG2TableView", 7 | "license": "", 8 | "scripts": { 9 | "typings": "typings", 10 | "webpack": "webpack", 11 | "webpack-dev-server": "webpack-dev-server", 12 | "webdriver-manager": "webdriver-manager", 13 | "clean": "npm cache clean && npm run rimraf -- node_modules doc typings coverage dist", 14 | "clean:dist": "npm run rimraf -- dist", 15 | "preclean:install": "npm run clean", 16 | "clean:install": "npm set progress=false && npm install", 17 | "preclean:start": "npm run clean", 18 | "clean:start": "npm start", 19 | "watch": "npm run watch:dev", 20 | "watch:dev": "npm run build:dev -- --watch", 21 | "watch:dev:hmr": "npm run watch:dev -- --hot", 22 | "watch:test": "npm run test -- --auto-watch --no-single-run", 23 | "watch:prod": "npm run build:prod -- --watch", 24 | "build": "npm run build:dev", 25 | "build:dev": "webpack --config config/webpack.dev.js --progress --profile --colors --display-error-details --display-cached", 26 | "build:prod": "webpack --config config/webpack.prod.js --progress --profile --colors --display-error-details --display-cached --bail", 27 | "server": "npm run server:dev", 28 | "server:dev": "webpack-dev-server --config config/webpack.dev.js --progress --profile --watch --content-base src/", 29 | "server:dev:hmr": "npm run server:dev -- --hot", 30 | "server:prod": "http-server dist --cors", 31 | "webdriver:update": "npm run webdriver-manager update", 32 | "webdriver:start": "npm run webdriver-manager start", 33 | "lint": "npm run tslint 'src/**/*.ts'", 34 | "start": "npm run server:dev", 35 | "start:hmr": "npm run server:dev:hmr", 36 | "preversion": "npm test" 37 | }, 38 | "dependencies": { 39 | "@angular/animations": "^5.0.0", 40 | "@angular/cdk": "^2.0.0-beta.12", 41 | "@angular/common": "^5.0.0", 42 | "@angular/compiler": "^5.0.0", 43 | "@angular/core": "^5.0.0", 44 | "@angular/forms": "^5.0.0", 45 | "@angular/http": "^5.0.0", 46 | "@angular/material": "^2.0.0-beta.12", 47 | "@angular/platform-browser": "^5.0.0", 48 | "@angular/platform-browser-dynamic": "^5.0.0", 49 | "@angular/platform-server": "^5.0.0", 50 | "@angular/router": "^5.0.0", 51 | "core-js": "^2.4.1", 52 | "lodash": "4.17.4", 53 | "moment": "2.21.0", 54 | "rxjs": "^5.4.3", 55 | "zone.js": "~0.8.18" 56 | }, 57 | "devDependencies": { 58 | "@angular/cli": "1.4.8", 59 | "@angular/compiler-cli": "^5.0.0", 60 | "@angular/language-service": "^4.2.4", 61 | "@types/jasmine": "~2.5.53", 62 | "@types/jasminewd2": "~2.0.2", 63 | "@types/lodash": "4.14.78", 64 | "@types/node": "~6.0.60", 65 | "@types/zone.js": "0.0.27", 66 | "codelyzer": "~3.2.0", 67 | "jasmine-core": "~2.6.2", 68 | "jasmine-spec-reporter": "~4.1.0", 69 | "karma": "~1.7.0", 70 | "karma-chrome-launcher": "~2.1.1", 71 | "karma-cli": "~1.0.1", 72 | "karma-coverage-istanbul-reporter": "^1.2.1", 73 | "karma-jasmine": "~1.1.0", 74 | "karma-jasmine-html-reporter": "^0.2.2", 75 | "protractor": "~5.1.2", 76 | "ts-node": "~3.2.0", 77 | "tslint": "~5.7.0", 78 | "typescript": "2.4.0", 79 | "webpack": "^3.8.1", 80 | "webpack-sources": "^1.0.1" 81 | }, 82 | "keywords": [ 83 | "angular2", 84 | "ng2", 85 | "angularjs", 86 | "table", 87 | "tableView", 88 | "grid", 89 | "filter", 90 | "sort" 91 | ], 92 | "repository": { 93 | "type": "git", 94 | "url": "https://github.com/dennis-b/NG2TableView" 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/demo/app/app.component.css: -------------------------------------------------------------------------------- 1 | /*@import '~@angular/material/prebuilt-themes/deeppurple-amber.css';*/ -------------------------------------------------------------------------------- /src/demo/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 |
7 | 8 | 9 | 10 |
11 | 12 | 13 |
14 | 15 |
16 | 17 |
18 | -------------------------------------------------------------------------------- /src/demo/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, ViewEncapsulation} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app', 5 | encapsulation: ViewEncapsulation.None, 6 | templateUrl: './app.component.html', 7 | styleUrls: ['./app.component.css'] 8 | }) 9 | export class AppComponent { 10 | constructor() { 11 | 12 | } 13 | 14 | ngOnInit() { 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/demo/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { HttpClientModule } from '@angular/common/http'; 5 | 6 | import { AppComponent } from './app.component'; 7 | import { Page } from "../pages/ng2-table-view-test/page"; 8 | 9 | import { routing } from './app.routes'; 10 | import { DataService } from "../pages/service/data.service"; 11 | import { Ng2TableViewModule } from "../../ng2-table-view"; 12 | 13 | @NgModule({ 14 | imports: [BrowserModule, FormsModule, HttpClientModule, Ng2TableViewModule, routing], 15 | declarations: [AppComponent, Page], 16 | providers: [DataService], 17 | bootstrap: [AppComponent] 18 | }) 19 | export class AppModule { 20 | } -------------------------------------------------------------------------------- /src/demo/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import {Page} from "../pages/ng2-table-view-test/page"; 2 | import {DataService} from "../pages/service/data.service"; 3 | 4 | import {Routes, RouterModule} from '@angular/router'; 5 | 6 | export const routes: Routes = [ 7 | {path: '', redirectTo: 'home', pathMatch: 'full'}, 8 | { 9 | path: 'home', 10 | component: Page, 11 | resolve: { 12 | users: DataService 13 | } 14 | } 15 | ]; 16 | 17 | export const routing = RouterModule.forRoot(routes); 18 | 19 | -------------------------------------------------------------------------------- /src/demo/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennis-b/NG2TableView/27f85864b8c7b76d3816d65d76d57aaefdeb7d4e/src/demo/assets/.gitkeep -------------------------------------------------------------------------------- /src/demo/assets/data/data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "_id": "573993ae2703194674cf814e", 4 | "index": 0, 5 | "guid": "4333f497-52a6-45e3-964e-d29609701121", 6 | "isActive": true, 7 | "age": 32, 8 | "name": "Melanie Wood", 9 | "gender": "female", 10 | "company": "MEDALERT", 11 | "email": "melaniewood@medalert.com", 12 | "phone": "+1 (966) 578-2624", 13 | "address": "195 Oceanic Avenue, Salvo, Hawaii, 4383", 14 | "location": { 15 | "latitude": -11.034383, 16 | "longitude": 6.870216 17 | } 18 | }, 19 | { 20 | "selected": false, 21 | "_id": "573993aedac66b479224ea46", 22 | "index": 1, 23 | "guid": "d1259480-03e1-47d7-b2fb-299c80257f31", 24 | "isActive": true, 25 | "age": 26, 26 | "name": "Stanley Nash", 27 | "gender": "male", 28 | "company": "INQUALA", 29 | "email": "stanleynash@inquala.com", 30 | "phone": "+1 (814) 462-3019", 31 | "address": "460 Kings Hwy, Rowe, Minnesota, 3461", 32 | "location": { 33 | "latitude": 79.633722, 34 | "longitude": -144.300448 35 | } 36 | }, 37 | { 38 | "selected": false, 39 | "_id": "573993aed6801e5b736252ea", 40 | "index": 2, 41 | "guid": "72dde627-1eb0-4d16-af0f-82428c01734f", 42 | "isActive": false, 43 | "age": 36, 44 | "name": "Dickson Thompson", 45 | "gender": "male", 46 | "company": "BARKARAMA", 47 | "email": "dicksonthompson@barkarama.com", 48 | "phone": "+1 (830) 529-3854", 49 | "address": "779 Lake Place, Caledonia, West Virginia, 8319", 50 | "location": { 51 | "latitude": 57.092497, 52 | "longitude": -130.567201 53 | } 54 | }, 55 | { 56 | "selected": false, 57 | "_id": "573993ae57160abf9cc46a8a", 58 | "index": 3, 59 | "guid": "d589b9fe-71c4-496f-a529-39deab06cbb5", 60 | "isActive": true, 61 | "age": 36, 62 | "name": "Melendez Lamb", 63 | "gender": "male", 64 | "company": "ZILLANET", 65 | "email": "melendezlamb@zillanet.com", 66 | "phone": "+1 (890) 487-3323", 67 | "address": "865 Montieth Street, Rivereno, Wisconsin, 9043", 68 | "location": { 69 | "latitude": -56.781567, 70 | "longitude": 116.643395 71 | } 72 | }, 73 | { 74 | "selected": false, 75 | "_id": "573993aee3ec6cdbb5b8e70b", 76 | "index": 4, 77 | "guid": "3f90f339-5510-4d13-9e3b-2ac113d909dd", 78 | "isActive": true, 79 | "age": 35, 80 | "name": "Buckner Reeves", 81 | "gender": "male", 82 | "company": "CONCILITY", 83 | "email": "bucknerreeves@concility.com", 84 | "phone": "+1 (807) 567-3465", 85 | "address": "744 Ryerson Street, Elbert, Nevada, 1462", 86 | "location": { 87 | "latitude": -6.28904, 88 | "longitude": 100.308181 89 | } 90 | }, 91 | { 92 | "selected": false, 93 | "_id": "573993aecfd88d20ecf091b9", 94 | "index": 5, 95 | "guid": "875defdb-8ce9-49d6-9ee9-837ce3007583", 96 | "isActive": false, 97 | "age": 30, 98 | "name": "Sellers May", 99 | "gender": "male", 100 | "company": "WAZZU", 101 | "email": "sellersmay@wazzu.com", 102 | "phone": "+1 (886) 564-3451", 103 | "address": "416 Middagh Street, Fairforest, Missouri, 2218", 104 | "location": { 105 | "latitude": -81.808813, 106 | "longitude": 135.843756 107 | } 108 | }, 109 | { 110 | "selected": false, 111 | "_id": "573993aede1707175fa5a69a", 112 | "index": 6, 113 | "guid": "7a5b667d-006b-4c88-842a-47d28bc2118f", 114 | "isActive": false, 115 | "age": 38, 116 | "name": "Love Silva", 117 | "gender": "male", 118 | "company": "MITROC", 119 | "email": "lovesilva@mitroc.com", 120 | "phone": "+1 (817) 460-3132", 121 | "address": "314 Nautilus Avenue, Accoville, Nebraska, 6761", 122 | "location": { 123 | "latitude": -40.883031, 124 | "longitude": 127.35034 125 | } 126 | }, 127 | { 128 | "selected": false, 129 | "_id": "573993aece6c17a0cadaf9c2", 130 | "index": 7, 131 | "guid": "b8092427-e56f-4478-9456-668d4c1893e5", 132 | "isActive": false, 133 | "age": 29, 134 | "name": "Waller Duncan", 135 | "gender": "male", 136 | "company": "EMOLTRA", 137 | "email": "wallerduncan@emoltra.com", 138 | "phone": "+1 (821) 503-2472", 139 | "address": "834 Albemarle Road, Fedora, Arizona, 7355", 140 | "location": { 141 | "latitude": -31.145593, 142 | "longitude": 85.350774 143 | } 144 | }, 145 | { 146 | "selected": false, 147 | "_id": "573993aeb41df20d55dd5d30", 148 | "index": 8, 149 | "guid": "96200410-8571-48fd-9ee2-9dbfaaed575e", 150 | "isActive": false, 151 | "age": 21, 152 | "name": "Brennan Mercer", 153 | "gender": "male", 154 | "company": "GRUPOLI", 155 | "email": "brennanmercer@grupoli.com", 156 | "phone": "+1 (885) 522-2478", 157 | "address": "488 Neptune Court, Rockbridge, Georgia, 9981", 158 | "location": { 159 | "latitude": 83.401842, 160 | "longitude": -142.528793 161 | } 162 | }, 163 | { 164 | "selected": false, 165 | "_id": "573993ae95ff7a58b160442f", 166 | "index": 9, 167 | "guid": "64fe93b4-4571-42b7-8cd5-13a793516da3", 168 | "isActive": false, 169 | "age": 27, 170 | "name": "Leila Hull", 171 | "gender": "female", 172 | "company": "VOIPA", 173 | "email": "leilahull@voipa.com", 174 | "phone": "+1 (934) 556-2208", 175 | "address": "244 Union Avenue, Madaket, Texas, 3111", 176 | "location": { 177 | "latitude": 31.429591, 178 | "longitude": -165.080848 179 | } 180 | }, 181 | { 182 | "selected": false, 183 | "_id": "573993ae3b572d83a764edfe", 184 | "index": 10, 185 | "guid": "bcdc2cb2-e31d-404b-b6ea-813d8f10cd86", 186 | "isActive": true, 187 | "age": 27, 188 | "name": "Madeline Haney", 189 | "gender": "female", 190 | "company": "COMTRAK", 191 | "email": "madelinehaney@comtrak.com", 192 | "phone": "+1 (928) 593-2441", 193 | "address": "881 Bogart Street, Inkerman, Oregon, 7592", 194 | "location": { 195 | "latitude": 63.319333, 196 | "longitude": 99.514697 197 | } 198 | }, 199 | { 200 | "selected": false, 201 | "_id": "573993aeb785a6632c22730c", 202 | "index": 11, 203 | "guid": "7b2a164f-7952-41b5-bf2a-d0afec0bdc54", 204 | "isActive": true, 205 | "age": 20, 206 | "name": "Heath Michael", 207 | "gender": "male", 208 | "company": "ZAGGLES", 209 | "email": "heathmichael@zaggles.com", 210 | "phone": "+1 (921) 484-2635", 211 | "address": "483 Jerome Street, Valle, South Carolina, 6045", 212 | "location": { 213 | "latitude": 57.806838, 214 | "longitude": 160.196472 215 | } 216 | }, 217 | { 218 | "selected": false, 219 | "_id": "573993aefc86b4e6be39684f", 220 | "index": 12, 221 | "guid": "32b6747e-ed0f-4e66-9860-e4ad84b1b241", 222 | "isActive": true, 223 | "age": 30, 224 | "name": "Wolf Mcfadden", 225 | "gender": "male", 226 | "company": "FURNAFIX", 227 | "email": "wolfmcfadden@furnafix.com", 228 | "phone": "+1 (836) 526-3977", 229 | "address": "747 Jamison Lane, Wintersburg, Maryland, 6324", 230 | "location": { 231 | "latitude": 33.079337, 232 | "longitude": 136.103739 233 | } 234 | }, 235 | { 236 | "selected": false, 237 | "_id": "573993aed031f7ea8a086cd9", 238 | "index": 13, 239 | "guid": "12112065-7e6d-46db-90c4-d8d584ad5e34", 240 | "isActive": true, 241 | "age": 21, 242 | "name": "Mclaughlin Malone", 243 | "gender": "male", 244 | "company": "TELEPARK", 245 | "email": "mclaughlinmalone@telepark.com", 246 | "phone": "+1 (994) 576-2893", 247 | "address": "689 Division Place, Wheatfields, Florida, 3119", 248 | "location": { 249 | "latitude": 30.353386, 250 | "longitude": -173.554489 251 | } 252 | }, 253 | { 254 | "selected": false, 255 | "_id": "573993aea2d2dc336a6ec158", 256 | "index": 14, 257 | "guid": "be167bbd-86c8-4cc9-a7ee-87d97896e283", 258 | "isActive": false, 259 | "age": 38, 260 | "name": "Ramona Jacobs", 261 | "gender": "female", 262 | "company": "PANZENT", 263 | "email": "ramonajacobs@panzent.com", 264 | "phone": "+1 (878) 571-3208", 265 | "address": "440 Rockaway Avenue, Stewartville, Tennessee, 8048", 266 | "location": { 267 | "latitude": 55.362032, 268 | "longitude": 73.8517 269 | } 270 | }, 271 | { 272 | "selected": false, 273 | "_id": "573993aeb952f94d5be1ab72", 274 | "index": 15, 275 | "guid": "4d7ae292-1c71-4e59-9ac7-33c7ced57cbc", 276 | "isActive": true, 277 | "age": 23, 278 | "name": "Kendra Baldwin", 279 | "gender": "female", 280 | "company": "PROTODYNE", 281 | "email": "kendrabaldwin@protodyne.com", 282 | "phone": "+1 (998) 498-3051", 283 | "address": "372 Brightwater Avenue, Avalon, District Of Columbia, 8056", 284 | "location": { 285 | "latitude": -54.241494, 286 | "longitude": 105.046496 287 | } 288 | }, 289 | { 290 | "selected": false, 291 | "_id": "573993aeed00b8482e7e7417", 292 | "index": 16, 293 | "guid": "0d0204ba-7ab4-4599-b9a4-0e1c0ff2f290", 294 | "isActive": true, 295 | "age": 27, 296 | "name": "Kayla Rosario", 297 | "gender": "female", 298 | "company": "QUADEEBO", 299 | "email": "kaylarosario@quadeebo.com", 300 | "phone": "+1 (934) 527-2299", 301 | "address": "396 Calyer Street, Iberia, Washington, 9201", 302 | "location": { 303 | "latitude": -4.862219, 304 | "longitude": -68.900603 305 | } 306 | }, 307 | { 308 | "selected": false, 309 | "_id": "573993aec1b612595925b8fd", 310 | "index": 17, 311 | "guid": "d7543505-773a-4b2c-978a-63cdeffa6385", 312 | "isActive": true, 313 | "age": 21, 314 | "name": "Ortega Lawrence", 315 | "gender": "male", 316 | "company": "INFOTRIPS", 317 | "email": "ortegalawrence@infotrips.com", 318 | "phone": "+1 (961) 589-3349", 319 | "address": "691 Luquer Street, Manchester, Montana, 4158", 320 | "location": { 321 | "latitude": 84.705468, 322 | "longitude": 119.962543 323 | } 324 | }, 325 | { 326 | "selected": false, 327 | "_id": "573993ae067732583fdd1d37", 328 | "index": 18, 329 | "guid": "a21de5d7-af0a-4c54-ab3f-47cb3db205c5", 330 | "isActive": false, 331 | "age": 35, 332 | "name": "Katharine Weber", 333 | "gender": "female", 334 | "company": "ENQUILITY", 335 | "email": "katharineweber@enquility.com", 336 | "phone": "+1 (848) 412-2147", 337 | "address": "934 Radde Place, Nanafalia, Massachusetts, 3908", 338 | "location": { 339 | "latitude": 30.335191, 340 | "longitude": -28.632988 341 | } 342 | }, 343 | { 344 | "selected": false, 345 | "_id": "573993ae29feeca35af2347a", 346 | "index": 19, 347 | "guid": "c1d9af1e-129e-4487-beb8-8b5a2e5bd9c1", 348 | "isActive": false, 349 | "age": 39, 350 | "name": "Floyd Ward", 351 | "gender": "male", 352 | "company": "CANDECOR", 353 | "email": "floydward@candecor.com", 354 | "phone": "+1 (832) 447-3637", 355 | "address": "895 Conselyea Street, Tuskahoma, North Dakota, 6895", 356 | "location": { 357 | "latitude": 55.446886, 358 | "longitude": 124.182314 359 | } 360 | }, 361 | { 362 | "selected": false, 363 | "_id": "573993ae74cc8e6ae9bab81b", 364 | "index": 20, 365 | "guid": "b54fb8a6-5a18-4545-92df-eab7556449b0", 366 | "isActive": false, 367 | "age": 35, 368 | "name": "Slater Delacruz", 369 | "gender": "male", 370 | "company": "FRANSCENE", 371 | "email": "slaterdelacruz@franscene.com", 372 | "phone": "+1 (957) 488-3505", 373 | "address": "322 Commerce Street, Roeville, Connecticut, 1334", 374 | "location": { 375 | "latitude": -17.295119, 376 | "longitude": -51.309209 377 | } 378 | }, 379 | { 380 | "selected": false, 381 | "_id": "573993aeeb57255d0100365c", 382 | "index": 21, 383 | "guid": "891d3233-2e43-462f-b1c1-b6053c2ac882", 384 | "isActive": false, 385 | "age": 40, 386 | "name": "Santos Stephens", 387 | "gender": "male", 388 | "company": "HANDSHAKE", 389 | "email": "santosstephens@handshake.com", 390 | "phone": "+1 (803) 586-3427", 391 | "address": "411 Wolcott Street, Machias, American Samoa, 5243", 392 | "location": { 393 | "latitude": 27.472245, 394 | "longitude": -102.771988 395 | } 396 | }, 397 | { 398 | "selected": false, 399 | "_id": "573993aeb60b3eaa6f584281", 400 | "index": 22, 401 | "guid": "98ad11e8-e75a-49c6-93e8-63d810712df9", 402 | "isActive": false, 403 | "age": 40, 404 | "name": "Bertha Green", 405 | "gender": "female", 406 | "company": "DUFLEX", 407 | "email": "berthagreen@duflex.com", 408 | "phone": "+1 (964) 464-3757", 409 | "address": "235 Lafayette Avenue, Topaz, New York, 1738", 410 | "location": { 411 | "latitude": 4.003851, 412 | "longitude": 179.124734 413 | } 414 | }, 415 | { 416 | "selected": false, 417 | "_id": "573993ae6c864fbca22a2e18", 418 | "index": 23, 419 | "guid": "6760d8c8-a3fb-4c94-8c28-8fd15dd93b6c", 420 | "isActive": false, 421 | "age": 27, 422 | "name": "Moss Fields", 423 | "gender": "male", 424 | "company": "EMTRAK", 425 | "email": "mossfields@emtrak.com", 426 | "phone": "+1 (876) 491-2736", 427 | "address": "101 Dahl Court, Caroleen, Arkansas, 5618", 428 | "location": { 429 | "latitude": -4.983119, 430 | "longitude": -178.129003 431 | } 432 | }, 433 | { 434 | "selected": false, 435 | "_id": "573993aeb2cf72d72e771e9e", 436 | "index": 24, 437 | "guid": "028fb7b0-750b-44bf-a0c6-d8f1f9c5f221", 438 | "isActive": true, 439 | "age": 29, 440 | "name": "Cooley Mcintosh", 441 | "gender": "male", 442 | "company": "NEBULEAN", 443 | "email": "cooleymcintosh@nebulean.com", 444 | "phone": "+1 (984) 505-3365", 445 | "address": "187 Ferry Place, Nicholson, Indiana, 3690", 446 | "location": { 447 | "latitude": -19.135964, 448 | "longitude": 91.93451 449 | } 450 | }, 451 | { 452 | "selected": false, 453 | "_id": "573993aed7dfc21adc501bac", 454 | "index": 25, 455 | "guid": "6e8d988f-47bb-4161-90d2-4b2ab4a54cb3", 456 | "isActive": false, 457 | "age": 33, 458 | "name": "Wolfe Bryan", 459 | "gender": "male", 460 | "company": "GEEKOL", 461 | "email": "wolfebryan@geekol.com", 462 | "phone": "+1 (871) 506-2271", 463 | "address": "427 Lake Street, Caln, Palau, 4732", 464 | "location": { 465 | "latitude": 35.309811, 466 | "longitude": -40.786291 467 | } 468 | }, 469 | { 470 | "selected": false, 471 | "_id": "573993ae456002cc370ff554", 472 | "index": 26, 473 | "guid": "5fb720fb-7d29-440c-b0a5-7550d2900d31", 474 | "isActive": false, 475 | "age": 34, 476 | "name": "Hoffman Ray", 477 | "gender": "male", 478 | "company": "SKYPLEX", 479 | "email": "hoffmanray@skyplex.com", 480 | "phone": "+1 (878) 589-2005", 481 | "address": "891 Beayer Place, Jeff, Colorado, 6946", 482 | "location": { 483 | "latitude": 30.871897, 484 | "longitude": 40.888203 485 | } 486 | }, 487 | { 488 | "selected": false, 489 | "_id": "573993ae7a0ade206bf99383", 490 | "index": 27, 491 | "guid": "46ce7d37-ffca-4022-9376-0ff0aabd6efa", 492 | "isActive": false, 493 | "age": 33, 494 | "name": "Margie Sweeney", 495 | "gender": "female", 496 | "company": "MELBACOR", 497 | "email": "margiesweeney@melbacor.com", 498 | "phone": "+1 (955) 550-2051", 499 | "address": "523 Verona Place, Walker, Wyoming, 9275", 500 | "location": { 501 | "latitude": 52.753725, 502 | "longitude": 73.367964 503 | } 504 | }, 505 | { 506 | "selected": false, 507 | "_id": "573993ae9769b50c2fafd6cc", 508 | "index": 28, 509 | "guid": "5539d51a-b275-4c90-a7dd-f61313dfdbd9", 510 | "isActive": false, 511 | "age": 25, 512 | "name": "Compton Bauer", 513 | "gender": "male", 514 | "company": "DANCITY", 515 | "email": "comptonbauer@dancity.com", 516 | "phone": "+1 (874) 441-3688", 517 | "address": "500 Colby Court, Weogufka, Vermont, 2105", 518 | "location": { 519 | "latitude": 18.040251, 520 | "longitude": 130.097237 521 | } 522 | }, 523 | { 524 | "selected": false, 525 | "_id": "573993aed46c7224aa38aae2", 526 | "index": 29, 527 | "guid": "6b73c9a7-8b45-41cc-8352-16955cf967cf", 528 | "isActive": false, 529 | "age": 23, 530 | "name": "Rosemarie Valentine", 531 | "gender": "female", 532 | "company": "ENTROPIX", 533 | "email": "rosemarievalentine@entropix.com", 534 | "phone": "+1 (847) 419-2538", 535 | "address": "318 Independence Avenue, Cashtown, South Dakota, 1930", 536 | "location": { 537 | "latitude": -57.808629, 538 | "longitude": -55.879557 539 | } 540 | }, 541 | { 542 | "selected": false, 543 | "_id": "573993aed9f4e3460c65bc05", 544 | "index": 30, 545 | "guid": "62e3853c-46b4-4277-badd-f28df518bfc2", 546 | "isActive": false, 547 | "age": 30, 548 | "name": "Leann Ross", 549 | "gender": "female", 550 | "company": "QUILTIGEN", 551 | "email": "leannross@quiltigen.com", 552 | "phone": "+1 (833) 513-3336", 553 | "address": "906 Kay Court, Southview, Utah, 8914", 554 | "location": { 555 | "latitude": -55.780972, 556 | "longitude": -75.932371 557 | } 558 | }, 559 | { 560 | "selected": false, 561 | "_id": "573993aea7b28b36dbbd6004", 562 | "index": 31, 563 | "guid": "4b5d7c1d-bb95-4d44-9cec-6ec3e6554c9a", 564 | "isActive": true, 565 | "age": 30, 566 | "name": "Griffith Carr", 567 | "gender": "male", 568 | "company": "DOGNOSIS", 569 | "email": "griffithcarr@dognosis.com", 570 | "phone": "+1 (858) 568-2321", 571 | "address": "341 Kiely Place, Glendale, New Hampshire, 5592", 572 | "location": { 573 | "latitude": -3.33499, 574 | "longitude": 80.856813 575 | } 576 | }, 577 | { 578 | "selected": false, 579 | "_id": "573993ae71a311fd861477c1", 580 | "index": 32, 581 | "guid": "19387373-9543-4422-bbb5-4c57cf6cbe01", 582 | "isActive": true, 583 | "age": 32, 584 | "name": "Harrison Bradshaw", 585 | "gender": "male", 586 | "company": "ONTALITY", 587 | "email": "harrisonbradshaw@ontality.com", 588 | "phone": "+1 (904) 518-3640", 589 | "address": "492 Billings Place, Cazadero, Virgin Islands, 945", 590 | "location": { 591 | "latitude": -18.905378, 592 | "longitude": 126.805519 593 | } 594 | }, 595 | { 596 | "selected": false, 597 | "_id": "573993ae289fefc27e2d6ee0", 598 | "index": 33, 599 | "guid": "ed678b12-c094-4414-b748-1ba22e52a7ef", 600 | "isActive": true, 601 | "age": 27, 602 | "name": "Myers Cabrera", 603 | "gender": "male", 604 | "company": "XELEGYL", 605 | "email": "myerscabrera@xelegyl.com", 606 | "phone": "+1 (872) 551-2782", 607 | "address": "876 Vista Place, Stockwell, Federated States Of Micronesia, 8636", 608 | "location": { 609 | "latitude": 27.455511, 610 | "longitude": -63.440019 611 | } 612 | }, 613 | { 614 | "selected": false, 615 | "_id": "573993aef3ac27d37c84c587", 616 | "index": 34, 617 | "guid": "277fd83b-be11-4a8b-b95a-823967fc362c", 618 | "isActive": true, 619 | "age": 28, 620 | "name": "Solis Martin", 621 | "gender": "male", 622 | "company": "PHOLIO", 623 | "email": "solismartin@pholio.com", 624 | "phone": "+1 (985) 583-3869", 625 | "address": "982 Woodside Avenue, Tilleda, Kansas, 9740", 626 | "location": { 627 | "latitude": -35.22439, 628 | "longitude": 32.783616 629 | } 630 | }, 631 | { 632 | "selected": false, 633 | "_id": "573993aec06db641e13e84d8", 634 | "index": 35, 635 | "guid": "c045914b-5886-44cb-af52-30112e4f3812", 636 | "isActive": true, 637 | "age": 28, 638 | "name": "Hattie Gutierrez", 639 | "gender": "female", 640 | "company": "PLAYCE", 641 | "email": "hattiegutierrez@playce.com", 642 | "phone": "+1 (892) 500-2594", 643 | "address": "212 Hale Avenue, Hoagland, Pennsylvania, 8761", 644 | "location": { 645 | "latitude": 83.359542, 646 | "longitude": -0.200791 647 | } 648 | }, 649 | { 650 | "selected": false, 651 | "_id": "573993ae516f1be6dda3465f", 652 | "index": 36, 653 | "guid": "c2481473-c9de-4a87-8ea3-2583f6d54d76", 654 | "isActive": true, 655 | "age": 21, 656 | "name": "Graham Bowen", 657 | "gender": "male", 658 | "company": "EGYPTO", 659 | "email": "grahambowen@egypto.com", 660 | "phone": "+1 (805) 569-3587", 661 | "address": "640 Amber Street, Marysville, Ohio, 9376", 662 | "location": { 663 | "latitude": 9.961157, 664 | "longitude": -58.715351 665 | } 666 | }, 667 | { 668 | "selected": false, 669 | "_id": "573993aee21f784d4181d257", 670 | "index": 37, 671 | "guid": "a567be0a-8aa4-4f25-ae15-9d22a59b59c8", 672 | "isActive": false, 673 | "age": 23, 674 | "name": "Vinson Cooke", 675 | "gender": "male", 676 | "company": "JASPER", 677 | "email": "vinsoncooke@jasper.com", 678 | "phone": "+1 (889) 588-3007", 679 | "address": "981 Logan Street, Brambleton, Michigan, 3964", 680 | "location": { 681 | "latitude": 58.454557, 682 | "longitude": 18.034208 683 | } 684 | }, 685 | { 686 | "selected": false, 687 | "_id": "573993ae0fc8112422c2a5c8", 688 | "index": 38, 689 | "guid": "63331e63-1662-4402-b7b6-17d02d805827", 690 | "isActive": false, 691 | "age": 22, 692 | "name": "Mitzi Shepard", 693 | "gender": "female", 694 | "company": "PLASMOSIS", 695 | "email": "mitzishepard@plasmosis.com", 696 | "phone": "+1 (842) 427-3330", 697 | "address": "889 Harbor Court, Delwood, Virginia, 6084", 698 | "location": { 699 | "latitude": -57.435899, 700 | "longitude": 150.378101 701 | } 702 | }, 703 | { 704 | "selected": false, 705 | "_id": "573993ae5a0b418713ac00ab", 706 | "index": 39, 707 | "guid": "f24ea19c-aec3-47be-ba1f-a00c6c501f27", 708 | "isActive": true, 709 | "age": 33, 710 | "name": "Underwood Turner", 711 | "gender": "male", 712 | "company": "AMTAS", 713 | "email": "underwoodturner@amtas.com", 714 | "phone": "+1 (896) 581-3256", 715 | "address": "804 Wyckoff Street, Lithium, Rhode Island, 7000", 716 | "location": { 717 | "latitude": -35.748952, 718 | "longitude": -138.320352 719 | } 720 | }, 721 | { 722 | "selected": false, 723 | "_id": "573993aea3f5500ad48e377a", 724 | "index": 40, 725 | "guid": "cb3457a2-7e9c-42a2-94af-159208287dd0", 726 | "isActive": false, 727 | "age": 34, 728 | "name": "Daisy Mathis", 729 | "gender": "female", 730 | "company": "FORTEAN", 731 | "email": "daisymathis@fortean.com", 732 | "phone": "+1 (942) 441-3963", 733 | "address": "561 Baltic Street, Graball, Alaska, 3725", 734 | "location": { 735 | "latitude": 23.020434, 736 | "longitude": -147.866958 737 | } 738 | }, 739 | { 740 | "selected": false, 741 | "_id": "573993ae67d453447a20095b", 742 | "index": 41, 743 | "guid": "50a43f66-b26b-4b7e-ae60-6bf3910a11bd", 744 | "isActive": false, 745 | "age": 24, 746 | "name": "Jerri Marsh", 747 | "gender": "female", 748 | "company": "ECRATIC", 749 | "email": "jerrimarsh@ecratic.com", 750 | "phone": "+1 (863) 518-3009", 751 | "address": "570 Ovington Avenue, Geyserville, California, 1950", 752 | "location": { 753 | "latitude": 57.750268, 754 | "longitude": 106.555837 755 | } 756 | }, 757 | { 758 | "selected": false, 759 | "_id": "573993ae696e0ab1319313bf", 760 | "index": 42, 761 | "guid": "e40de97a-67b8-4995-8357-947999e782e0", 762 | "isActive": true, 763 | "age": 34, 764 | "name": "Craig Kirby", 765 | "gender": "male", 766 | "company": "MULTRON", 767 | "email": "craigkirby@multron.com", 768 | "phone": "+1 (977) 536-3133", 769 | "address": "930 Rutledge Street, Canby, New Jersey, 4547", 770 | "location": { 771 | "latitude": 67.184783, 772 | "longitude": -146.676475 773 | } 774 | }, 775 | { 776 | "selected": false, 777 | "_id": "573993ae8f8c17aa087c301b", 778 | "index": 43, 779 | "guid": "6da64e61-dc03-48b8-80b8-6fbe0ee45151", 780 | "isActive": true, 781 | "age": 32, 782 | "name": "Mills Pena", 783 | "gender": "male", 784 | "company": "ZOMBOID", 785 | "email": "millspena@zomboid.com", 786 | "phone": "+1 (844) 600-3138", 787 | "address": "311 Lombardy Street, Indio, Kentucky, 659", 788 | "location": { 789 | "latitude": 30.871757, 790 | "longitude": -23.762959 791 | } 792 | }, 793 | { 794 | "selected": false, 795 | "_id": "573993ae9fec8949c5a91a5e", 796 | "index": 44, 797 | "guid": "ec26aa2b-2660-4168-97da-c4450a4cc51f", 798 | "isActive": true, 799 | "age": 29, 800 | "name": "Ronda Larson", 801 | "gender": "female", 802 | "company": "NIXELT", 803 | "email": "rondalarson@nixelt.com", 804 | "phone": "+1 (893) 416-3026", 805 | "address": "275 Polar Street, Clinton, Oklahoma, 577", 806 | "location": { 807 | "latitude": 85.474921, 808 | "longitude": -30.804319 809 | } 810 | }, 811 | { 812 | "selected": false, 813 | "_id": "573993ae7794a6adcbd543aa", 814 | "index": 45, 815 | "guid": "c1b92785-55f8-40d7-8651-6d39c363a7f5", 816 | "isActive": false, 817 | "age": 24, 818 | "name": "Allison Whitfield", 819 | "gender": "male", 820 | "company": "GEEKFARM", 821 | "email": "allisonwhitfield@geekfarm.com", 822 | "phone": "+1 (822) 401-2367", 823 | "address": "447 Llama Court, Bentonville, Guam, 3962", 824 | "location": { 825 | "latitude": -30.232955, 826 | "longitude": 48.024692 827 | } 828 | }, 829 | { 830 | "selected": false, 831 | "_id": "573993ae615c932e0db0403f", 832 | "index": 46, 833 | "guid": "75c4608b-0332-4357-bbe4-fe278551912c", 834 | "isActive": true, 835 | "age": 34, 836 | "name": "Myrtle Dillon", 837 | "gender": "female", 838 | "company": "ENERVATE", 839 | "email": "myrtledillon@enervate.com", 840 | "phone": "+1 (949) 422-2926", 841 | "address": "972 Banker Street, Fidelis, North Carolina, 8237", 842 | "location": { 843 | "latitude": 11.505916, 844 | "longitude": 19.373057 845 | } 846 | }, 847 | { 848 | "selected": false, 849 | "_id": "573993ae8ed359d25395a835", 850 | "index": 47, 851 | "guid": "a1473415-6228-439a-9160-506ae7ada5e2", 852 | "isActive": false, 853 | "age": 37, 854 | "name": "Stokes Mason", 855 | "gender": "male", 856 | "company": "ZOLAR", 857 | "email": "stokesmason@zolar.com", 858 | "phone": "+1 (854) 574-3967", 859 | "address": "606 Box Street, Wildwood, Idaho, 5537", 860 | "location": { 861 | "latitude": 70.405526, 862 | "longitude": -158.367754 863 | } 864 | }, 865 | { 866 | "selected": false, 867 | "_id": "573993aefd2f425f48652059", 868 | "index": 48, 869 | "guid": "fe954bf9-f41a-4ebf-ac9c-10266e860f78", 870 | "isActive": true, 871 | "age": 28, 872 | "name": "Mcmillan Klein", 873 | "gender": "male", 874 | "company": "COMSTRUCT", 875 | "email": "mcmillanklein@comstruct.com", 876 | "phone": "+1 (954) 501-3947", 877 | "address": "731 Coyle Street, Ironton, Delaware, 2270", 878 | "location": { 879 | "latitude": 2.242745, 880 | "longitude": -88.486638 881 | } 882 | }, 883 | { 884 | "selected": false, 885 | "_id": "573993ae30793353308fbc68", 886 | "index": 49, 887 | "guid": "1b5fca94-d54f-462b-addd-811f875fc0d7", 888 | "isActive": true, 889 | "age": 27, 890 | "name": "Gillespie Higgins", 891 | "gender": "male", 892 | "company": "BOILICON", 893 | "email": "gillespiehiggins@boilicon.com", 894 | "phone": "+1 (826) 590-3584", 895 | "address": "120 Cortelyou Road, Logan, Iowa, 3509", 896 | "location": { 897 | "latitude": -67.465181, 898 | "longitude": -119.557997 899 | } 900 | }, 901 | { 902 | "selected": false, 903 | "_id": "573993ae4d5420c78fece56e", 904 | "index": 50, 905 | "guid": "934883b9-072e-40a0-ab27-7a5c06fbe740", 906 | "isActive": false, 907 | "age": 25, 908 | "name": "Prince Gonzales", 909 | "gender": "male", 910 | "company": "ACCIDENCY", 911 | "email": "princegonzales@accidency.com", 912 | "phone": "+1 (822) 545-3393", 913 | "address": "861 Barlow Drive, Kennedyville, Maine, 6995", 914 | "location": { 915 | "latitude": -22.408006, 916 | "longitude": -162.976633 917 | } 918 | }, 919 | { 920 | "selected": false, 921 | "_id": "573993ae62f4228968da6300", 922 | "index": 51, 923 | "guid": "22775aeb-b7d5-4800-b093-ef555e30517d", 924 | "isActive": true, 925 | "age": 26, 926 | "name": "Kitty Bird", 927 | "gender": "female", 928 | "company": "JUMPSTACK", 929 | "email": "kittybird@jumpstack.com", 930 | "phone": "+1 (857) 585-3129", 931 | "address": "497 Herkimer Street, Hayes, Northern Mariana Islands, 836", 932 | "location": { 933 | "latitude": -9.263732, 934 | "longitude": 4.170385 935 | } 936 | }, 937 | { 938 | "selected": false, 939 | "_id": "573993ae3cf71166109f60bc", 940 | "index": 52, 941 | "guid": "6023dc54-d3b5-413c-8535-c2d41d5d6eff", 942 | "isActive": false, 943 | "age": 35, 944 | "name": "Josefina Pace", 945 | "gender": "female", 946 | "company": "GEEKETRON", 947 | "email": "josefinapace@geeketron.com", 948 | "phone": "+1 (986) 478-3334", 949 | "address": "526 Grove Street, Vivian, Puerto Rico, 363", 950 | "location": { 951 | "latitude": -21.309574, 952 | "longitude": -122.748342 953 | } 954 | }, 955 | { 956 | "selected": false, 957 | "_id": "573993aeba8832a4e231da38", 958 | "index": 53, 959 | "guid": "bbb4ebe1-e00b-45b8-977a-d2a61d03a12e", 960 | "isActive": false, 961 | "age": 20, 962 | "name": "Lee Blackwell", 963 | "gender": "female", 964 | "company": "PROSURE", 965 | "email": "leeblackwell@prosure.com", 966 | "phone": "+1 (999) 509-2835", 967 | "address": "676 Canda Avenue, Rosedale, Alabama, 8917", 968 | "location": { 969 | "latitude": 67.84182, 970 | "longitude": 73.851267 971 | } 972 | }, 973 | { 974 | "selected": false, 975 | "_id": "573993aeef01e83451ec9eec", 976 | "index": 54, 977 | "guid": "810cfeea-a37b-4a4c-be8f-20bcf01b69d9", 978 | "isActive": true, 979 | "age": 25, 980 | "name": "Graciela Gamble", 981 | "gender": "female", 982 | "company": "SKYBOLD", 983 | "email": "gracielagamble@skybold.com", 984 | "phone": "+1 (817) 588-3627", 985 | "address": "657 Vandervoort Place, Ryderwood, Illinois, 8377", 986 | "location": { 987 | "latitude": -84.05646, 988 | "longitude": -50.420858 989 | } 990 | }, 991 | { 992 | "selected": false, 993 | "_id": "573993aee7965529ed6a91dd", 994 | "index": 55, 995 | "guid": "d2ef1b48-51d0-47ca-9f37-a3e7da059eb1", 996 | "isActive": true, 997 | "age": 20, 998 | "name": "Browning Hewitt", 999 | "gender": "male", 1000 | "company": "BEDLAM", 1001 | "email": "browninghewitt@bedlam.com", 1002 | "phone": "+1 (994) 409-3161", 1003 | "address": "414 Overbaugh Place, Blanford, Louisiana, 5172", 1004 | "location": { 1005 | "latitude": 8.231031, 1006 | "longitude": -32.840017 1007 | } 1008 | }, 1009 | { 1010 | "selected": false, 1011 | "_id": "573993aeb9115ae400ff14f4", 1012 | "index": 56, 1013 | "guid": "f766e657-0e17-4836-b4b1-3d891f1f4b38", 1014 | "isActive": false, 1015 | "age": 29, 1016 | "name": "Murphy Livingston", 1017 | "gender": "male", 1018 | "company": "ERSUM", 1019 | "email": "murphylivingston@ersum.com", 1020 | "phone": "+1 (940) 444-3327", 1021 | "address": "174 Glendale Court, Wacissa, New Mexico, 811", 1022 | "location": { 1023 | "latitude": 75.200607, 1024 | "longitude": -58.987263 1025 | } 1026 | }, 1027 | { 1028 | "selected": false, 1029 | "_id": "573993aeab8ee84d6edc15e1", 1030 | "index": 57, 1031 | "guid": "68c67488-fd6a-4cab-9dc9-521225b0d2ee", 1032 | "isActive": false, 1033 | "age": 31, 1034 | "name": "Vilma Humphrey", 1035 | "gender": "female", 1036 | "company": "ZISIS", 1037 | "email": "vilmahumphrey@zisis.com", 1038 | "phone": "+1 (928) 422-3605", 1039 | "address": "303 Gardner Avenue, Hessville, Mississippi, 1509", 1040 | "location": { 1041 | "latitude": 64.489015, 1042 | "longitude": -11.915495 1043 | } 1044 | }, 1045 | { 1046 | "selected": false, 1047 | "_id": "573993aea4a25a2e5b3c4231", 1048 | "index": 58, 1049 | "guid": "08b6f063-0900-4675-b092-80a2a2d266f2", 1050 | "isActive": false, 1051 | "age": 31, 1052 | "name": "Candy Estrada", 1053 | "gender": "female", 1054 | "company": "VELOS", 1055 | "email": "candyestrada@velos.com", 1056 | "phone": "+1 (913) 488-2280", 1057 | "address": "833 Elm Avenue, Cartwright, Hawaii, 842", 1058 | "location": { 1059 | "latitude": -8.361387, 1060 | "longitude": -99.601379 1061 | } 1062 | }, 1063 | { 1064 | "selected": false, 1065 | "_id": "573993aea0b460a52fc0596d", 1066 | "index": 59, 1067 | "guid": "1cbef17f-48b6-4de6-8829-84074aa35892", 1068 | "isActive": true, 1069 | "age": 33, 1070 | "name": "Goldie Rhodes", 1071 | "gender": "female", 1072 | "company": "COMVOY", 1073 | "email": "goldierhodes@comvoy.com", 1074 | "phone": "+1 (936) 556-2240", 1075 | "address": "289 Hull Street, Sanborn, Minnesota, 5783", 1076 | "location": { 1077 | "latitude": -74.658434, 1078 | "longitude": -41.359811 1079 | } 1080 | }, 1081 | { 1082 | "selected": false, 1083 | "_id": "573993ae643109f774dce886", 1084 | "index": 60, 1085 | "guid": "d06300e5-d813-45f8-9abe-a067f344e365", 1086 | "isActive": true, 1087 | "age": 23, 1088 | "name": "Mccray Chen", 1089 | "gender": "male", 1090 | "company": "CYCLONICA", 1091 | "email": "mccraychen@cyclonica.com", 1092 | "phone": "+1 (855) 498-2004", 1093 | "address": "558 Banner Avenue, Wattsville, West Virginia, 4498", 1094 | "location": { 1095 | "latitude": -69.595801, 1096 | "longitude": -126.27813 1097 | } 1098 | }, 1099 | { 1100 | "selected": false, 1101 | "_id": "573993ae6d1684a322d5a9ee", 1102 | "index": 61, 1103 | "guid": "03b870ee-be95-4f71-91d1-b305c2e45171", 1104 | "isActive": false, 1105 | "age": 24, 1106 | "name": "Foley Hancock", 1107 | "gender": "male", 1108 | "company": "ZILLIDIUM", 1109 | "email": "foleyhancock@zillidium.com", 1110 | "phone": "+1 (843) 513-2333", 1111 | "address": "706 Glen Street, Bodega, Wisconsin, 5553", 1112 | "location": { 1113 | "latitude": -20.968664, 1114 | "longitude": -116.232093 1115 | } 1116 | }, 1117 | { 1118 | "selected": false, 1119 | "_id": "573993ae0edc32f05802c0fc", 1120 | "index": 62, 1121 | "guid": "d924fa59-3708-4687-a30b-9469ba6446dd", 1122 | "isActive": true, 1123 | "age": 23, 1124 | "name": "Beach Stuart", 1125 | "gender": "male", 1126 | "company": "TOURMANIA", 1127 | "email": "beachstuart@tourmania.com", 1128 | "phone": "+1 (821) 473-2169", 1129 | "address": "996 Fulton Street, Davenport, Nevada, 853", 1130 | "location": { 1131 | "latitude": -28.639559, 1132 | "longitude": -67.689828 1133 | } 1134 | } 1135 | ] -------------------------------------------------------------------------------- /src/demo/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/demo/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /src/demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NG2TableView 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Loading... 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/demo/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.log(err)); 13 | -------------------------------------------------------------------------------- /src/demo/pages/ng2-table-view-test/cols/columns.ts: -------------------------------------------------------------------------------- 1 | import { ColumnIfc, TableColumn, TableColumns, SortTypes } from "../../../../ng2-table-view"; 2 | 3 | 4 | const customTemplate = ` 5 | 6 | ` 7 | 8 | export const PageTableColumns: Array = new TableColumns() 9 | .addCol(new TableColumn() 10 | .setTitle("index") 11 | .setName("index") 12 | .setSort(true) 13 | .setSortType(SortTypes.DESCENDING) // setting initial sorting 14 | ) 15 | .addCol(new TableColumn() 16 | .setTitle("Editable name ") 17 | .setName("name") 18 | .setTemplate(customTemplate) 19 | .setSort(true) 20 | ) 21 | .addCol(new TableColumn() 22 | .setTitle("gender") 23 | .setName("gender") 24 | ) 25 | .addCol(new TableColumn() 26 | .setTitle("company") 27 | .setName("company") 28 | ) 29 | .addCol(new TableColumn() 30 | .setTitle("email") 31 | .setName("email") 32 | ) 33 | .addCol(new TableColumn() 34 | .setTitle("latitude") 35 | .setName("location.latitude") 36 | ) 37 | .addCol(new TableColumn() 38 | .setTitle("longitude") 39 | .setName("location.longitude") 40 | ) 41 | .getCols(); 42 | -------------------------------------------------------------------------------- /src/demo/pages/ng2-table-view-test/index.ts: -------------------------------------------------------------------------------- 1 | export * from './page'; 2 | -------------------------------------------------------------------------------- /src/demo/pages/ng2-table-view-test/page.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 | 7 | 8 | 15 | 16 | 17 | 18 | 25 | 26 | 27 |
28 | 29 | 30 | 34 | 35 | 36 |
37 | 40 | 41 |
42 | 43 |
44 | 45 | 46 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /src/demo/pages/ng2-table-view-test/page.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { PageTableColumns } from "./cols/columns"; 3 | import { TableView, SortTypes } from "../../../ng2-table-view"; 4 | import { ActivatedRoute } from "@angular/router"; 5 | 6 | @Component({ 7 | selector: "demo-page", 8 | templateUrl: './page.html' 9 | }) 10 | export class Page extends TableView implements OnInit { 11 | 12 | constructor(private route: ActivatedRoute) { 13 | // super(route.data.getValue().users); 14 | super(route.snapshot.data['users']) 15 | } 16 | 17 | ngOnInit() { 18 | const builder = this.getBuilder(); 19 | builder.addCols(PageTableColumns) 20 | .setPaging(true) 21 | .setItemsPerPage(5) 22 | .setSelectable(true); 23 | 24 | this.buildTable(); 25 | 26 | this.setColumnSortable('email', SortTypes.DESCENDING); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/demo/pages/service/data.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router'; 3 | 4 | import { HttpClient } from '@angular/common/http'; 5 | import { Observable } from "rxjs/Rx"; 6 | 7 | @Injectable() 8 | export class DataService implements Resolve { 9 | 10 | 11 | constructor(private http: HttpClient) { 12 | } 13 | 14 | resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | Promise | any { 15 | return this.http.get('demo/assets/data/data.json') 16 | .map(data => data) 17 | 18 | } 19 | } -------------------------------------------------------------------------------- /src/demo/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** IE10 and IE11 requires the following for the Reflect API. */ 41 | // import 'core-js/es6/reflect'; 42 | 43 | 44 | /** Evergreen browsers require these. **/ 45 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 46 | import 'core-js/es7/reflect'; 47 | 48 | 49 | /** 50 | * Required to support Web Animations `@angular/platform-browser/animations`. 51 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation 52 | **/ 53 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 54 | 55 | 56 | /*************************************************************************************************** 57 | * Zone JS is required by Angular itself. 58 | */ 59 | import 'zone.js/dist/zone'; // Included with Angular CLI. 60 | 61 | 62 | /*************************************************************************************************** 63 | * APPLICATION IMPORTS 64 | */ 65 | 66 | /** 67 | * Date, currency, decimal and percent pipes. 68 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 69 | */ 70 | // import 'intl'; // Run `npm install --save intl`. 71 | /** 72 | * Need to import at least one locale-data with intl. 73 | */ 74 | // import 'intl/locale-data/jsonp/en'; 75 | 76 | import 'rxjs/add/operator/map'; -------------------------------------------------------------------------------- /src/demo/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | @import '~@angular/material/prebuilt-themes/deeppurple-amber.css'; -------------------------------------------------------------------------------- /src/demo/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "../", 6 | "module": "es2015", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /src/demo/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/demo/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | 4 | interface NodeModule { 5 | id: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/demo/utils/app-utils.ts: -------------------------------------------------------------------------------- 1 | import { Injector } from '@angular/core'; 2 | 3 | let appInjectorRef:Injector; 4 | export const setInjector = (injector?:Injector) => { 5 | if (injector) { 6 | appInjectorRef = injector; 7 | } 8 | }; 9 | 10 | 11 | export const getInjector = ():Injector => { 12 | return appInjectorRef; 13 | }; 14 | 15 | 16 | export class Utils { 17 | 18 | static appInjectorRef:Injector = getInjector(); 19 | 20 | static getService(service) { 21 | return appInjectorRef.get(service); 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/ng2-table-view/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Dennis 3 | */ 4 | export * from './ng2-table-view'; 5 | export * from './table.view.module'; -------------------------------------------------------------------------------- /src/ng2-table-view/ng2-table-view.ts: -------------------------------------------------------------------------------- 1 | import {NgTableView} from "./table/table"; 2 | import {Ng2TableViewSortable} from "./table/directive/sorting"; 3 | import {NgTableViewPaging} from "./table/directive/paging/paging"; 4 | import {Ng2TableViewFilter} from "./table/directive/filtering"; 5 | 6 | export const NG_TABLE_VIEW_DIRECTIVES = [NgTableView, Ng2TableViewFilter, NgTableViewPaging, Ng2TableViewSortable]; 7 | 8 | export * from './table/config/ColumnIfc'; 9 | export * from './table/config/ConfigBuilder'; 10 | export * from './table/config/TableColumn'; 11 | export * from './table/config/TableColumns'; 12 | export * from './table/config/TableView'; 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/ng2-table-view/table-material.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { MatCheckboxModule, MatIconModule, MatInputModule, MatIconRegistry } from '@angular/material'; 3 | 4 | 5 | @NgModule({ 6 | imports: [MatInputModule, MatCheckboxModule, MatIconModule], 7 | exports: [MatInputModule, MatCheckboxModule, MatIconModule], 8 | providers: [ 9 | MatIconRegistry 10 | ] 11 | }) 12 | export class TableMaterialModule { 13 | } -------------------------------------------------------------------------------- /src/ng2-table-view/table.view.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 5 | import { NgTableView } from "./table/table"; 6 | import { TableCell } from "./table/directive/table-cell-custom-template"; 7 | import { Ng2TableViewSortable } from "./table/directive/sorting"; 8 | import { NgTableViewPaging } from "./table/directive/paging/paging"; 9 | import { Ng2TableViewFilter } from "./table/directive/filtering"; 10 | import NestedTableDataPipe from "./table/pipes/nested-table-data-pipe"; 11 | import TableDataPipe from "./table/pipes/table-data-pipe"; 12 | import { TableMaterialModule } from './table-material.module'; 13 | 14 | @NgModule({ 15 | imports: [ 16 | BrowserModule, 17 | BrowserAnimationsModule, 18 | FormsModule, 19 | TableMaterialModule 20 | ], 21 | 22 | declarations: [ 23 | NgTableView, 24 | Ng2TableViewSortable, 25 | NgTableViewPaging, 26 | Ng2TableViewFilter, 27 | NestedTableDataPipe, 28 | TableDataPipe, 29 | TableCell 30 | ], 31 | 32 | 33 | exports: [ 34 | NgTableView, 35 | NgTableViewPaging, 36 | Ng2TableViewFilter, 37 | TableMaterialModule 38 | ] 39 | }) 40 | export class Ng2TableViewModule { 41 | } -------------------------------------------------------------------------------- /src/ng2-table-view/table/config/ColumnIfc.ts: -------------------------------------------------------------------------------- 1 | export interface ColumnIfc { 2 | title:String; 3 | name:String; 4 | modal:Boolean; 5 | uiFilter:String; 6 | sort:Boolean; 7 | template:String; 8 | sortType?: SortTypes; 9 | } 10 | 11 | 12 | export enum SortTypes { 13 | ASCENDING = "asc", 14 | DESCENDING = "desc" 15 | } -------------------------------------------------------------------------------- /src/ng2-table-view/table/config/ConfigBuilder.ts: -------------------------------------------------------------------------------- 1 | import { ColumnIfc } from "./ColumnIfc"; 2 | import { SortTypes } from '../../index'; 3 | 4 | /** 5 | * Created by Dennis on 27/04/2016. 6 | */ 7 | export class TableConfigBuilder { 8 | 9 | public data: Array = []; 10 | public rows: Array = []; 11 | public filtered: Array = []; 12 | public columns: Array = []; 13 | public page: number = 1; 14 | public itemsPerPage: number = 10; 15 | public numPages: number = 1; 16 | public length: number = 0; 17 | public paging: boolean = false; 18 | public sorting: any = {columns: []}; 19 | public filtering: any = {}; 20 | public selectable: boolean = false; 21 | 22 | constructor(data: Array) { 23 | this.data = data; 24 | this.length = data.length; 25 | } 26 | 27 | addCol(col: ColumnIfc) { 28 | this.columns.push(col); 29 | return this; 30 | } 31 | 32 | insertCol(index: number, col: ColumnIfc) { 33 | this.columns.splice(index, 0, col); 34 | return this; 35 | } 36 | 37 | addCols(cols: Array) { 38 | Array.prototype.push.apply(this.columns, cols); 39 | return this; 40 | } 41 | 42 | setItemsPerPage(itemsPerPage: number) { 43 | this.itemsPerPage = itemsPerPage; 44 | return this; 45 | } 46 | 47 | 48 | setNumPages(numPages: number) { 49 | this.numPages = numPages; 50 | return this; 51 | } 52 | 53 | setPaging(paging: boolean) { 54 | this.paging = paging; 55 | return this; 56 | } 57 | 58 | setSorting(sorting: any) { 59 | this.sorting = sorting; 60 | return this; 61 | } 62 | 63 | setFiltering(filtering: any) { 64 | this.filtering = filtering; 65 | return this; 66 | } 67 | 68 | setSelectable(selectable: boolean) { 69 | this.selectable = selectable; 70 | return this; 71 | } 72 | 73 | 74 | setData(data: Array) { 75 | this.data = data; 76 | this.length = data.length; 77 | return this; 78 | } 79 | 80 | setColumnSortable(name: string, sortType: SortTypes) { 81 | const col = this.columns.find(({name: colName}) => colName && name.toLowerCase() === colName.toLowerCase()) 82 | if (col) { 83 | col.sort = true; 84 | col.sortType = sortType 85 | } 86 | this.sorting.columns = [col] 87 | return this; 88 | } 89 | 90 | setInitSort() { 91 | const sorting = [] 92 | this.columns.forEach(col => col.sortType && sorting.push(col)) 93 | this.sorting.columns = [...this.sorting.columns, ...sorting]; 94 | return this; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/ng2-table-view/table/config/SelectTableColumn.ts: -------------------------------------------------------------------------------- 1 | import { TableColumn } from "./TableColumn"; 2 | 3 | 4 | const template = `` 5 | 6 | 7 | export class SelectTableColumn extends TableColumn { 8 | private selectable: boolean = true; 9 | 10 | constructor() { 11 | super(); 12 | this.setTemplate(template); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/ng2-table-view/table/config/TableColumn.ts: -------------------------------------------------------------------------------- 1 | import { ColumnIfc, SortTypes } from "./ColumnIfc"; 2 | 3 | 4 | 5 | export class TableColumn implements ColumnIfc { 6 | 7 | title: string; 8 | name: string; 9 | modal: boolean; 10 | uiFilter: string; 11 | sort: boolean; 12 | sortType: SortTypes; 13 | template: string; 14 | 15 | constructor() { 16 | 17 | } 18 | 19 | setTitle(title: string) { 20 | this.title = title; 21 | return this; 22 | } 23 | 24 | setName(name: string) { 25 | this.name = name; 26 | return this; 27 | } 28 | 29 | setModal(modal: boolean) { 30 | this.modal = modal; 31 | return this; 32 | } 33 | 34 | setSort(sort: boolean) { 35 | this.sort = sort; 36 | return this; 37 | 38 | } 39 | 40 | setSortType(sortType: SortTypes) { 41 | this.sortType = sortType; 42 | return this; 43 | } 44 | 45 | setUiFilter(uiFilter: string) { 46 | this.uiFilter = uiFilter; 47 | return this; 48 | } 49 | 50 | setTemplate(template: string) { 51 | this.template = template; 52 | return this; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/ng2-table-view/table/config/TableColumns.ts: -------------------------------------------------------------------------------- 1 | import {ColumnIfc} from "./ColumnIfc"; 2 | 3 | export class TableColumns { 4 | 5 | private tableColumns:Array = []; 6 | 7 | constructor() { 8 | } 9 | 10 | addCol(col:ColumnIfc) { 11 | this.tableColumns.push(col); 12 | return this; 13 | } 14 | 15 | getCols():Array { 16 | return this.tableColumns; 17 | } 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/ng2-table-view/table/config/TableView.ts: -------------------------------------------------------------------------------- 1 | import { TableConfigBuilder } from "./ConfigBuilder"; 2 | import * as _ from 'lodash' 3 | import { SelectTableColumn } from "./SelectTableColumn"; 4 | import { SortTypes } from './ColumnIfc'; 5 | 6 | export class TableView { 7 | 8 | public tableData: Array = []; 9 | public tableBuilder: TableConfigBuilder; 10 | 11 | constructor(data?) { 12 | this.tableBuilder = new TableConfigBuilder(data || []); 13 | } 14 | 15 | setData(data: any) { 16 | this.tableBuilder.setData(data); 17 | return this.tableBuilder; 18 | } 19 | 20 | getBuilder() { 21 | return this.tableBuilder; 22 | } 23 | 24 | changePage(page: any, data: Array = this.tableBuilder.data): Array { 25 | let start = (page.page - 1) * page.itemsPerPage; 26 | if (start >= data.length) { 27 | return data.slice(0, data.length); 28 | } 29 | let end = page.itemsPerPage > -1 ? (start + page.itemsPerPage) : data.length; 30 | return data.slice(start, end); 31 | } 32 | 33 | changeSort(data: any, config: any) { 34 | if (!config.sorting || !config.sorting.columns || config.sorting.columns.length == 0) { 35 | return data; 36 | } 37 | let columns = this.tableBuilder.sorting.columns || []; 38 | let sorted = _.sortBy(data, columns[0].name); 39 | if (columns[0].sortType === SortTypes.DESCENDING) { 40 | sorted.reverse(); 41 | } 42 | return sorted; 43 | } 44 | 45 | changeFilter(data: any, config: any): any { 46 | if (!config.filtering || _.isEmpty(config.filtering)) { 47 | return data; 48 | } 49 | let filterKeys = _.keys(config.filtering); 50 | for (let i = 0; i < filterKeys.length; i++) { 51 | const filterKey = filterKeys[i]; 52 | data = data.filter((item) => { 53 | let calculatedItem = filterKey.split(".").reduce((a, b) => a ? a[b] : "", item); 54 | let filterString = this.tableBuilder.filtering[filterKey].filterString; 55 | return String(calculatedItem).toLowerCase().match(String(filterString).toLowerCase()) 56 | }) 57 | } 58 | return data; 59 | } 60 | 61 | buildTable() { 62 | if (this.tableBuilder.selectable) { 63 | this.tableBuilder.insertCol(0, new SelectTableColumn()) 64 | } 65 | 66 | this.onChangeTable(this.tableBuilder.setInitSort()); 67 | } 68 | 69 | onChangeTable(config?: any) { 70 | let data = this.getFilteredAndSortedData(config); 71 | this.tableBuilder.filtered = data; 72 | this.tableBuilder.rows = this.tableBuilder.paging ? this.changePage(this.tableBuilder, data) : data; 73 | this.tableBuilder.length = data.length; 74 | } 75 | 76 | getFilteredAndSortedData(config: any) { 77 | if (config && config.filtering) { 78 | Object.assign(this.tableBuilder.filtering, config.filtering); 79 | } 80 | 81 | if (config && config.sorting && config.sorting.length > 0) { 82 | this.tableBuilder.sorting = config.sorting; 83 | } 84 | 85 | let filteredData = this.changeFilter(this.tableBuilder.data, this.tableBuilder); 86 | return this.changeSort(filteredData, this.tableBuilder); 87 | } 88 | 89 | setColumnSortable(columnName: string, sortType: SortTypes) { 90 | this.tableBuilder.setColumnSortable(columnName, sortType); 91 | this.onChangeTable(this.tableBuilder.setColumnSortable(columnName, sortType)) 92 | } 93 | 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/ng2-table-view/table/directive/filtering.ts: -------------------------------------------------------------------------------- 1 | import {Directive, EventEmitter, ElementRef, Renderer, Input} from '@angular/core'; 2 | 3 | // import {setProperty} from 'angular2/ts/src/core/forms/directives/shared'; 4 | function setProperty(renderer:Renderer, elementRef:ElementRef, propName:string, propValue:any) { 5 | renderer.setElementProperty(elementRef, propName, propValue); 6 | } 7 | 8 | @Directive({ 9 | selector: '[ng2TableViewFilter]', 10 | outputs: ['tableChanged'], 11 | host: { 12 | '(input)': 'onChangeFilter($event.target.value)' 13 | } 14 | }) 15 | export class Ng2TableViewFilter { 16 | 17 | @Input('ng2TableFilter') public config:any = {}; 18 | @Input() public column:string; 19 | public tableChanged:EventEmitter = new EventEmitter(); 20 | 21 | constructor(private element:ElementRef, private renderer:Renderer) { 22 | 23 | } 24 | 25 | ngOnInit() { 26 | this.config[this.column] = {filterString: ""}; 27 | setProperty(this.renderer, this.element, 'value', this.config[this.column].filterString); 28 | // this.renderer.setElementProperty(this.element, 'value', this.config[this.column].filterString); 29 | } 30 | 31 | onChangeFilter(event:any) { 32 | this.config[this.column].filterString = event; 33 | this.tableChanged.emit({'filtering': this.config}); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/ng2-table-view/table/directive/paging/pagination.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 10 |
11 | 12 |
13 | 19 |
20 | 21 |
22 | 29 | 30 | 37 | 38 | 45 | 46 | 47 | 54 |
55 | 56 |
57 | -------------------------------------------------------------------------------- /src/ng2-table-view/table/directive/paging/paging.css: -------------------------------------------------------------------------------- 1 | .md-table-pagination { 2 | display: -webkit-flex; 3 | display: -ms-flexbox; 4 | display: flex; 5 | -webkit-align-items: center; 6 | -ms-flex-align: center; 7 | align-items: center; 8 | -webkit-justify-content: center; 9 | -ms-flex-pack: end; 10 | justify-content: center; 11 | -webkit-flex-wrap: wrap-reverse; 12 | -ms-flex-wrap: wrap-reverse; 13 | flex-wrap: wrap-reverse; 14 | box-sizing: border-box; 15 | padding: 0 24px; 16 | font-size: 12px; 17 | color: rgba(0, 0, 0, 0.54); 18 | border-top: 1px rgba(0, 0, 0, 0.12) solid; 19 | } 20 | 21 | .md-table-pagination md-select { 22 | -webkit-justify-content: flex-end; 23 | -ms-flex-pack: end; 24 | justify-content: flex-end; 25 | min-width: 64px; 26 | } 27 | 28 | .md-table-pagination md-select:not([disabled]):focus .md-select-value { 29 | color: rgba(0, 0, 0, 0.54); 30 | } 31 | 32 | .md-table-pagination md-select .md-select-value { 33 | -webkit-flex: 0 0 auto; 34 | -ms-flex: 0 0 auto; 35 | flex: 0 0 auto; 36 | } 37 | 38 | .md-table-pagination md-select .md-select-value span.md-select-icon { 39 | -webkit-justify-content: center; 40 | -ms-flex-pack: center; 41 | justify-content: center; 42 | text-align: center; 43 | margin-right: -6px !important; 44 | } 45 | 46 | .md-table-pagination md-select .md-select-value span.md-select-icon:after { 47 | top: initial; 48 | -webkit-transform: scaleY(0.5) scaleX(1); 49 | transform: scaleY(0.5) scaleX(1); 50 | } 51 | 52 | .md-table-pagination > * { 53 | display: -webkit-flex; 54 | display: -ms-flexbox; 55 | display: flex; 56 | -webkit-align-items: center; 57 | -ms-flex-align: center; 58 | align-items: center; 59 | height: 56px; 60 | } 61 | 62 | .md-table-pagination > .buttons:not(:first-child), 63 | .md-table-pagination > .limit-select:not(:first-child) { 64 | margin-left: 32px; 65 | } 66 | 67 | .md-table-pagination > .buttons { 68 | margin-right: -16px; 69 | } 70 | 71 | .md-table-pagination > .buttons > .md-button.md-icon-button { 72 | margin: 0; 73 | } 74 | 75 | .md-table-pagination > .buttons > .label + .md-button.md-icon-button { 76 | margin-left: 20px; 77 | } 78 | -------------------------------------------------------------------------------- /src/ng2-table-view/table/directive/paging/paging.ts: -------------------------------------------------------------------------------- 1 | import {Component, EventEmitter, ElementRef, Renderer, Input, OnChanges, SimpleChanges} from '@angular/core'; 2 | import * as _ from 'lodash' 3 | 4 | @Component({ 5 | selector: 'ngTableViewPaging', 6 | outputs: ['pageChanged'], 7 | templateUrl: './pagination.html', 8 | styleUrls: ['./paging.css'] 9 | }) 10 | export class NgTableViewPaging implements OnChanges { 11 | 12 | 13 | @Input() public config: any = {}; 14 | @Input() public dataLength: number = 0; 15 | 16 | public pageChanged: EventEmitter = new EventEmitter(); 17 | private totalPages: number = 1; 18 | private totalPagesArr: Array = []; 19 | 20 | constructor() { 21 | } 22 | 23 | ngOnChanges(changes: SimpleChanges): any { 24 | this.totalPages = this.calculateTotalPages(); 25 | this.totalPagesArr = new Array(this.totalPages); 26 | } 27 | 28 | ngOnInit() { 29 | this.totalPages = this.calculateTotalPages(); 30 | this.totalPagesArr = new Array(this.totalPages); 31 | 32 | } 33 | 34 | itemsPerPageSelect() { 35 | this.totalPages = this.calculateTotalPages(); 36 | this.totalPagesArr = new Array(this.totalPages); 37 | 38 | this.pageChanged.emit(this.config); 39 | } 40 | 41 | toNumber(val) { 42 | return Number(val); 43 | } 44 | 45 | calculateTotalPages() { 46 | const totalPages = this.config.itemsPerPage < 1 47 | ? 1 48 | : Math.ceil(this.dataLength / this.config.itemsPerPage); 49 | return Math.max(totalPages || 0, 1); 50 | } 51 | 52 | noNext() { 53 | return this.config.page == this.totalPages; 54 | } 55 | 56 | noPrevious() { 57 | return this.config.page == 1; 58 | }; 59 | 60 | onPageSelect() { 61 | this.selectPage(this.config.page, null); 62 | } 63 | 64 | selectPage(page, event) { 65 | if (!_.isEmpty(this.config) && page) { 66 | this.config.page = Number(page); 67 | this.pageChanged.emit(this.config); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/ng2-table-view/table/directive/sorting.ts: -------------------------------------------------------------------------------- 1 | import {Directive, EventEmitter, ElementRef} from '@angular/core'; 2 | import {EmitterService} from "../service/emitter.service"; 3 | import { SortTypes } from '../config/ColumnIfc'; 4 | 5 | @Directive({ 6 | selector: '[ng2TableViewSortable]', 7 | inputs: ['config: ng2TableViewSortable', 'column', 'index'], 8 | outputs: ['sortChanged'], 9 | providers: [EmitterService], 10 | host: { 11 | '(click)': 'onToggleSort($event, $target)', 12 | '[class.md-active]': 'active', 13 | } 14 | }) 15 | export class Ng2TableViewSortable { 16 | public active:boolean = false; 17 | public config:any; 18 | public column:any; 19 | public index:any; 20 | public sortChanged:EventEmitter = new EventEmitter(); 21 | 22 | constructor() { 23 | EmitterService.subscribe((index)=> { 24 | if (this.index != index) { 25 | this.active = false 26 | } 27 | }) 28 | } 29 | 30 | onToggleSort(event:any, target:any) { 31 | if (event) { 32 | event.preventDefault(); 33 | } 34 | 35 | EmitterService.emit(this.index); 36 | this.active = true; 37 | 38 | if (this.config && this.column && this.column.sort) { 39 | switch (this.column.sortType) { 40 | case SortTypes.ASCENDING: 41 | this.column.sortType = SortTypes.DESCENDING; 42 | break; 43 | case SortTypes.DESCENDING: 44 | this.column.sortType = SortTypes.ASCENDING; 45 | break; 46 | default: 47 | this.column.sortType = SortTypes.ASCENDING; 48 | break; 49 | } 50 | 51 | this.sortChanged.emit(this.column); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/ng2-table-view/table/directive/table-cell-custom-template.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Compiler, 3 | Component, 4 | Input, 5 | NgModule, 6 | OnInit, 7 | ReflectiveInjector, 8 | ViewChild, 9 | ViewContainerRef 10 | } from "@angular/core"; 11 | 12 | import { BrowserModule } from '@angular/platform-browser'; 13 | import { FormsModule } from '@angular/forms'; 14 | import { TableMaterialModule } from '../../table-material.module'; 15 | 16 | 17 | function compileToComponent(template, data) { 18 | @Component({ 19 | selector: 'cell', 20 | template: template 21 | }) 22 | class CellComponent { 23 | private cellData: any = {}; 24 | 25 | constructor() { 26 | this.cellData = data; 27 | } 28 | } 29 | 30 | @NgModule({ 31 | imports: [BrowserModule, FormsModule, TableMaterialModule], 32 | declarations: [CellComponent] 33 | }) 34 | class CellComponentModule { 35 | } 36 | 37 | return {CellComponentModule, CellComponent}; 38 | } 39 | 40 | @Component({ 41 | selector: 'table-cell', 42 | template: '
' 43 | }) 44 | export class TableCell implements OnInit { 45 | 46 | @ViewChild('target', {read: ViewContainerRef}) target; 47 | @Input() public cellTemplate: String = ''; 48 | @Input() public cellData: any = {}; 49 | 50 | constructor(private viewContainerRef: ViewContainerRef, private compiler: Compiler) { 51 | } 52 | 53 | ngOnInit() { 54 | const moduleType = compileToComponent(this.cellTemplate, this.cellData); 55 | this.compiler.compileModuleAndAllComponentsAsync(moduleType.CellComponentModule) 56 | .then(({componentFactories}) => { 57 | const compFactory = componentFactories.find(x => x.componentType === moduleType.CellComponent); 58 | const injector = ReflectiveInjector.fromResolvedProviders([], this.viewContainerRef.parentInjector); 59 | this.viewContainerRef.clear(); 60 | this.viewContainerRef.createComponent(compFactory, 0, injector); 61 | }); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/ng2-table-view/table/pipes/nested-table-data-pipe.ts: -------------------------------------------------------------------------------- 1 | import {PipeTransform, Pipe} from '@angular/core'; 2 | 3 | @Pipe({name: 'nestedTableData'}) 4 | export default class NestedTableDataPipe implements PipeTransform { 5 | transform(value:any, str:string):string { 6 | return str.split('.').reduce((a, b) => a ? a[b] : "-", value); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/ng2-table-view/table/pipes/table-data-pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import * as moment from 'moment' 3 | 4 | @Pipe({name: 'tableData', pure: false}) 5 | export default class TableDataPipe implements PipeTransform { 6 | transform(value: any, col: any = null, row: any = null): string { 7 | 8 | let val = col.name.split('.').reduce((a, b) => a ? a[b] : "-", row); 9 | if (col && col.uiFilter == 'json') { 10 | return JSON.stringify(val); 11 | } 12 | 13 | if (col && col.uiFilter == 'date') { 14 | return moment(val).format("DD/MM/YYYY : hh:mm"); 15 | } 16 | 17 | return value; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/ng2-table-view/table/service/emitter.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable, EventEmitter} from '@angular/core'; 2 | 3 | @Injectable() 4 | export class EmitterService { 5 | private static emitter:EventEmitter = new EventEmitter(); 6 | 7 | 8 | static getEmitter():EventEmitter { 9 | return this.emitter; 10 | } 11 | 12 | static emit(data:any) { 13 | this.emitter.emit(data); 14 | } 15 | 16 | static subscribe(fn) { 17 | this.emitter.subscribe(fn) 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /src/ng2-table-view/table/table.css: -------------------------------------------------------------------------------- 1 | md-backdrop.md-edit-dialog-backdrop { 2 | z-index: 80 3 | } 4 | 5 | md-edit-dialog { 6 | display: -webkit-flex; 7 | display: -ms-flexbox; 8 | display: flex; 9 | -webkit-flex-direction: column; 10 | -ms-flex-direction: column; 11 | flex-direction: column; 12 | position: fixed; 13 | z-index: 81; 14 | background-color: #f9f9f9; 15 | border-radius: 2px; 16 | cursor: default 17 | } 18 | 19 | md-edit-dialog > .md-content { 20 | padding: 16px 24px 0 21 | } 22 | 23 | md-edit-dialog > .md-content .md-title { 24 | color: rgba(0, 0, 0, .87); 25 | margin-bottom: 8px 26 | } 27 | 28 | md-edit-dialog > .md-content mat-input-container { 29 | margin: 0; 30 | font-size: 13px 31 | } 32 | 33 | md-edit-dialog > .md-content mat-input-container input { 34 | float: none 35 | } 36 | 37 | .md-table-pagination { 38 | display: -webkit-flex; 39 | display: -ms-flexbox; 40 | display: flex; 41 | -webkit-align-items: center; 42 | -ms-flex-align: center; 43 | align-items: center; 44 | -webkit-justify-content: flex-end; 45 | -ms-flex-pack: end; 46 | justify-content: flex-end; 47 | -webkit-flex-wrap: wrap-reverse; 48 | -ms-flex-wrap: wrap-reverse; 49 | flex-wrap: wrap-reverse; 50 | box-sizing: border-box; 51 | padding: 0 24px; 52 | font-size: 12px; 53 | color: rgba(0, 0, 0, .54); 54 | border-top: 1px rgba(0, 0, 0, .12) solid 55 | } 56 | 57 | .md-table-pagination md-select { 58 | -webkit-justify-content: flex-end; 59 | -ms-flex-pack: end; 60 | justify-content: flex-end; 61 | min-width: 64px 62 | } 63 | 64 | .md-table-pagination md-select:not([disabled]):focus .md-select-value { 65 | color: rgba(0, 0, 0, .54) 66 | } 67 | 68 | .md-table-pagination md-select .md-select-value { 69 | -webkit-flex: 0 0 auto; 70 | -ms-flex: 0 0 auto; 71 | flex: 0 0 auto 72 | } 73 | 74 | .md-table-pagination md-select .md-select-value span.md-select-icon { 75 | -webkit-justify-content: center; 76 | -ms-flex-pack: center; 77 | justify-content: center; 78 | text-align: center; 79 | margin-right: -6px !important 80 | } 81 | 82 | .md-table-pagination md-select .md-select-value span.md-select-icon:after { 83 | top: initial; 84 | -webkit-transform: scaleY(0.5) scaleX(1); 85 | transform: scaleY(0.5) scaleX(1) 86 | } 87 | 88 | .md-table-pagination > * { 89 | display: -webkit-flex; 90 | display: -ms-flexbox; 91 | display: flex; 92 | -webkit-align-items: center; 93 | -ms-flex-align: center; 94 | align-items: center; 95 | height: 56px 96 | } 97 | 98 | .md-table-pagination > .buttons:not(:first-child), .md-table-pagination > .limit-select:not(:first-child) { 99 | margin-left: 32px 100 | } 101 | 102 | .md-table-pagination > .buttons { 103 | margin-right: -16px 104 | } 105 | 106 | .md-table-pagination > .buttons > .md-button.mat-icon-button { 107 | margin: 0 108 | } 109 | 110 | .md-table-pagination > .buttons > .label + .md-button.mat-icon-button { 111 | margin-left: 20px 112 | } 113 | 114 | md-select.md-table-select { 115 | margin: 0 116 | } 117 | 118 | md-select.md-table-select > .md-select-value { 119 | padding: 0; 120 | min-width: 0; 121 | min-height: 24px; 122 | border-bottom: 0 !important 123 | } 124 | 125 | md-select.md-table-select > .md-select-value > span { 126 | display: block; 127 | height: auto; 128 | -webkit-transform: none !important; 129 | transform: none !important 130 | } 131 | 132 | md-select.md-table-select > .md-select-value > span > .md-text { 133 | display: inherit; 134 | height: inherit; 135 | -webkit-transform: inherit; 136 | transform: inherit 137 | } 138 | 139 | md-select.md-table-select > .md-select-value > span.md-select-icon { 140 | display: -webkit-flex; 141 | display: -ms-flexbox; 142 | display: flex; 143 | -webkit-align-items: center; 144 | -ms-flex-align: center; 145 | align-items: center; 146 | height: 24px; 147 | margin: 0 148 | } 149 | 150 | md-select.md-table-select > .md-select-value > span.md-select-icon:after { 151 | top: initial 152 | } 153 | 154 | .md-select-menu-container.md-pagination-select, .md-select-menu-container.md-table-select { 155 | margin-left: -2px; 156 | border-radius: 2px 157 | } 158 | 159 | .md-select-menu-container.md-pagination-select md-content, .md-select-menu-container.md-pagination-select md-select-menu, .md-select-menu-container.md-table-select md-content, .md-select-menu-container.md-table-select md-select-menu { 160 | border-radius: inherit 161 | } 162 | 163 | .md-select-menu-container.md-pagination-select md-content, .md-select-menu-container.md-table-select md-content { 164 | padding: 0 165 | } 166 | 167 | .md-select-menu-container.md-table-select .md-text { 168 | font-size: 13px 169 | } 170 | 171 | .md-select-menu-container.md-pagination-select .md-text { 172 | font-size: 12px 173 | } 174 | 175 | md-toolbar.md-table-toolbar { 176 | box-shadow: none 177 | } 178 | 179 | md-toolbar.md-table-toolbar.md-default-theme:not(.md-menu-toolbar).md-default, md-toolbar.md-table-toolbar:not(.md-menu-toolbar).md-default { 180 | background-color: #fff; 181 | color: rgba(0, 0, 0, .87) 182 | } 183 | 184 | md-toolbar.md-table-toolbar.md-default-theme:not(.md-menu-toolbar).md-default .md-button, md-toolbar.md-table-toolbar:not(.md-menu-toolbar).md-default .md-button { 185 | color: rgba(0, 0, 0, .87) 186 | } 187 | 188 | @media only screen and (max-width: 959px) and (min-width: 0) and (orientation: landscape) { 189 | md-toolbar.md-table-toolbar .md-toolbar-tools { 190 | height: 64px; 191 | max-height: initial 192 | } 193 | } 194 | 195 | md-toolbar.md-table-toolbar .md-toolbar-tools { 196 | padding: 0 24px 197 | } 198 | 199 | md-toolbar.md-table-toolbar .md-toolbar-tools mat-icon { 200 | color: rgba(0, 0, 0, .54) 201 | } 202 | 203 | md-toolbar.md-table-toolbar .md-toolbar-tools > .md-button.mat-icon-button { 204 | margin: 0 205 | } 206 | 207 | md-toolbar.md-table-toolbar .md-toolbar-tools > .md-button.mat-icon-button:first-child { 208 | margin-left: -12px 209 | } 210 | 211 | md-toolbar.md-table-toolbar .md-toolbar-tools > .md-button.mat-icon-button:last-child { 212 | margin-right: -12px 213 | } 214 | 215 | md-card > md-table-container:first-child, md-card > md-toolbar.md-table-toolbar:first-child { 216 | border-top-left-radius: 2px; 217 | border-top-right-radius: 2px 218 | } 219 | 220 | md-card > md-table-container:last-child, md-card > md-toolbar.md-table-toolbar:last-child { 221 | border-bottom-left-radius: 2px; 222 | border-bottom-right-radius: 2px 223 | } 224 | 225 | md-table-container { 226 | display: block; 227 | max-width: 100%; 228 | overflow-x: auto; 229 | -webkit-overflow-scrolling: touch 230 | } 231 | 232 | table.md-table { 233 | width: 100%; 234 | border-spacing: 0; 235 | overflow: hidden 236 | } 237 | 238 | table.md-table thead.md-head > tr.md-row { 239 | height: 56px 240 | } 241 | 242 | table.md-table tbody.md-body > tr.md-row, table.md-table tfoot.md-foot > tr.md-row { 243 | height: 48px 244 | } 245 | 246 | table.md-table thead.md-head + .md-table-progress md-progress-linear { 247 | top: -3px 248 | } 249 | 250 | table.md-table .md-table-progress th { 251 | padding: 0 252 | } 253 | 254 | table.md-table .md-table-progress th md-progress-linear { 255 | height: 0; 256 | transition: opacity 1s 257 | } 258 | 259 | table.md-table .md-table-progress th md-progress-linear.ng-hide { 260 | opacity: 0 261 | } 262 | 263 | table.md-table .md-table-progress th md-progress-linear > .md-container { 264 | height: 3px; 265 | top: 0; 266 | transition: none 267 | } 268 | 269 | table.md-table .md-table-progress th md-progress-linear > .md-container > .md-bar { 270 | height: 3px 271 | } 272 | 273 | table.md-table th.md-column { 274 | color: rgba(0, 0, 0, .54); 275 | font-size: 12px; 276 | font-weight: 700; 277 | white-space: nowrap 278 | } 279 | 280 | table.md-table th.md-column.md-sort a { 281 | cursor: pointer 282 | } 283 | 284 | table.md-table th.md-column mat-icon { 285 | height: 16px; 286 | width: 16px; 287 | font-size: 16px !important; 288 | line-height: 16px !important 289 | } 290 | 291 | table.md-table th.md-column mat-icon.md-sort-icon { 292 | color: rgba(0, 0, 0, .26); 293 | opacity: 0; 294 | transition: -webkit-transform .25s, opacity .25s; 295 | transition: transform .25s, opacity .25s 296 | } 297 | 298 | table.md-table th.md-column mat-icon.md-sort-icon.md-asc { 299 | -webkit-transform: rotate(0deg); 300 | transform: rotate(0deg) 301 | } 302 | 303 | table.md-table th.md-column mat-icon.md-sort-icon.md-desc { 304 | -webkit-transform: rotate(180deg); 305 | transform: rotate(180deg) 306 | } 307 | 308 | table.md-table th.md-column mat-icon:not(:first-child) { 309 | margin-left: 8px 310 | } 311 | 312 | table.md-table th.md-column mat-icon:not(:last-child) { 313 | margin-right: 8px 314 | } 315 | 316 | table.md-table th.md-column a.md-active, 317 | table.md-table th.md-column a.md-active mat-icon { 318 | color: rgba(0, 0, 0, .87) 319 | } 320 | 321 | table.md-table th.md-column a.md-active mat-icon.md-sort-icon, 322 | table.md-table th.md-column:hover mat-icon.md-sort-icon { 323 | opacity: 1 324 | } 325 | 326 | table.md-table tr.md-row[data-ng-repeat].ng-leave, table.md-table tr.md-row[ng-repeat].ng-leave, table.md-table tr.md-row[ng\:repeat].ng-leave, table.md-table tr.md-row[x-ng-repeat].ng-leave { 327 | display: none 328 | } 329 | 330 | table.md-table.md-row-select tbody.md-body > tr.md-row { 331 | transition: background-color .2s 332 | } 333 | 334 | table.md-table.md-row-select tbody.md-body > tr.md-row:not([disabled]):hover { 335 | background-color: #eee !important 336 | } 337 | 338 | table.md-table.md-row-select tbody.md-body > tr.md-row.md-selected { 339 | background-color: #f5f5f5 340 | } 341 | 342 | table.md-table.md-row-select td.md-cell:first-child, table.md-table.md-row-select th.md-column:first-child { 343 | width: 20px; 344 | padding: 0 0 0 24px 345 | } 346 | 347 | table.md-table.md-row-select td.md-cell:nth-child(2), table.md-table.md-row-select th.md-column:nth-child(2) { 348 | padding: 0 24px 349 | } 350 | 351 | table.md-table.md-row-select td.md-cell:nth-child(n+3):nth-last-child(n+2), table.md-table.md-row-select th.md-column:nth-child(n+3):nth-last-child(n+2) { 352 | padding: 0 56px 0 0; 353 | } 354 | 355 | table.md-table:not(.md-row-select) td.md-cell:first-child, table.md-table:not(.md-row-select) th.md-column:first-child { 356 | padding: 0 24px 357 | } 358 | 359 | table.md-table:not(.md-row-select) td.md-cell:nth-child(n+2):nth-last-child(n+2), table.md-table:not(.md-row-select) th.md-column:nth-child(n+2):nth-last-child(n+2) { 360 | padding: 0 56px 0 0 361 | } 362 | 363 | table.md-table td.md-cell, table.md-table th.md-column { 364 | vertical-align: middle; 365 | text-align: left 366 | } 367 | 368 | table.md-table td.md-cell .md-cell-data { 369 | max-height: 50px; 370 | max-width: 300px; 371 | overflow: hidden; 372 | display: inline-block; 373 | } 374 | 375 | table.md-table td.md-cell > *, table.md-table th.md-column > * { 376 | vertical-align: middle 377 | } 378 | 379 | table.md-table td.md-cell:last-child, table.md-table th.md-column:last-child { 380 | padding: 0 24px 0 0 381 | } 382 | 383 | table.md-table td.md-cell.md-clickable:focus, table.md-table th.md-column.md-clickable:focus { 384 | outline: 0 385 | } 386 | 387 | table.md-table td.md-cell.md-numeric, table.md-table th.md-column.md-numeric { 388 | text-align: right 389 | } 390 | 391 | table.md-table td.md-cell { 392 | color: rgba(0, 0, 0, .87); 393 | font-size: 13px; 394 | border-top: 1px grey solid; 395 | height: 55px; 396 | 397 | } 398 | 399 | table.md-table td.md-cell.md-numeric md-select { 400 | -webkit-justify-content: flex-end; 401 | -ms-flex-pack: end; 402 | justify-content: flex-end 403 | } 404 | 405 | table.md-table td.md-cell.md-numeric md-select .md-select-value { 406 | -webkit-flex: 0 0 auto; 407 | -ms-flex: 0 0 auto; 408 | flex: 0 0 auto 409 | } 410 | 411 | table.md-table td.md-cell.md-placeholder { 412 | color: rgba(0, 0, 0, .26) 413 | } 414 | 415 | table.md-table td.md-cell md-select > .md-select-value > span.md-select-icon { 416 | -webkit-justify-content: flex-end; 417 | -ms-flex-pack: end; 418 | justify-content: flex-end; 419 | color: rgba(0, 0, 0, .54); 420 | width: 18px; 421 | text-align: right 422 | } 423 | 424 | table.md-table td.md-cell md-select > .md-select-value > span.md-select-icon:after { 425 | -webkit-transform: scaleY(0.4) scaleX(0.8); 426 | transform: scaleY(0.4) scaleX(0.8) 427 | } 428 | 429 | table.md-table mat-checkbox { 430 | box-sizing: border-box; 431 | white-space: nowrap; 432 | cursor: pointer; 433 | outline: none; 434 | -webkit-user-select: none; 435 | -moz-user-select: none; 436 | -ms-user-select: none; 437 | user-select: none; 438 | position: relative; 439 | min-width: 20px; 440 | min-height: 20px; 441 | display: flex; 442 | margin-top: 15px; 443 | margin-bottom: 15px; 444 | } 445 | -------------------------------------------------------------------------------- /src/ng2-table-view/table/table.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 28 | 29 | 30 | 31 | 32 | 33 | 43 | 44 | 45 |
5 | 6 | 7 | 10 | 11 | 12 |
13 | {{column.title}} 14 |
15 | 16 | 21 | {{column.title}} 22 | 24 | arrow_downward 25 | 26 | 27 |
34 | 35 | 36 | 37 |
38 |
{{row | nestedTableData:column.name | tableData:column:row}}
39 |
40 | 41 |
42 |
46 | -------------------------------------------------------------------------------- /src/ng2-table-view/table/table.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Output } from '@angular/core'; 2 | import * as _ from 'lodash'; 3 | 4 | 5 | @Component({ 6 | selector: 'ng2TableView, [ng2TableView]', 7 | inputs: ['rows', 'columns', 'config'], 8 | templateUrl: './table.html', 9 | styleUrls: ['./table.css'], 10 | }) 11 | 12 | export class NgTableView { 13 | public rows: Array = []; 14 | public config: any = {}; 15 | private allSelected: any = {}; 16 | @Output() tableChanged: EventEmitter = new EventEmitter(); 17 | 18 | constructor() { 19 | } 20 | 21 | onAllSelected($event) { 22 | this.allSelected = $event.checked; 23 | this.config.data.map((item) => { 24 | item.selected = _.includes(this.config.filtered, item) ? this.allSelected : false; 25 | }); 26 | } 27 | 28 | onChangeTable(column: any) { 29 | this.tableChanged.emit({sorting: {columns: [column]}}); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/ng2-table-view/table/template/select.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "target": "es5", 11 | "typeRoots": [ 12 | "node_modules/@types" 13 | ], 14 | "lib": [ 15 | "es2017", 16 | "dom" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "eofline": true, 15 | "forin": true, 16 | "import-blacklist": [ 17 | true, 18 | "rxjs", 19 | "rxjs/Rx" 20 | ], 21 | "import-spacing": true, 22 | "indent": [ 23 | true, 24 | "spaces" 25 | ], 26 | "interface-over-type-literal": true, 27 | "label-position": true, 28 | "max-line-length": [ 29 | true, 30 | 140 31 | ], 32 | "member-access": false, 33 | "member-ordering": [ 34 | true, 35 | { 36 | "order": [ 37 | "static-field", 38 | "instance-field", 39 | "static-method", 40 | "instance-method" 41 | ] 42 | } 43 | ], 44 | "no-arg": true, 45 | "no-bitwise": true, 46 | "no-console": [ 47 | true, 48 | "debug", 49 | "info", 50 | "time", 51 | "timeEnd", 52 | "trace" 53 | ], 54 | "no-construct": true, 55 | "no-debugger": true, 56 | "no-duplicate-super": true, 57 | "no-empty": false, 58 | "no-empty-interface": true, 59 | "no-eval": true, 60 | "no-inferrable-types": [ 61 | true, 62 | "ignore-params" 63 | ], 64 | "no-misused-new": true, 65 | "no-non-null-assertion": true, 66 | "no-shadowed-variable": true, 67 | "no-string-literal": false, 68 | "no-string-throw": true, 69 | "no-switch-case-fall-through": true, 70 | "no-trailing-whitespace": true, 71 | "no-unnecessary-initializer": true, 72 | "no-unused-expression": true, 73 | "no-use-before-declare": true, 74 | "no-var-keyword": true, 75 | "object-literal-sort-keys": false, 76 | "one-line": [ 77 | true, 78 | "check-open-brace", 79 | "check-catch", 80 | "check-else", 81 | "check-whitespace" 82 | ], 83 | "prefer-const": true, 84 | "quotemark": [ 85 | true, 86 | "single" 87 | ], 88 | "radix": true, 89 | "semicolon": [ 90 | true, 91 | "always" 92 | ], 93 | "triple-equals": [ 94 | true, 95 | "allow-null-check" 96 | ], 97 | "typedef-whitespace": [ 98 | true, 99 | { 100 | "call-signature": "nospace", 101 | "index-signature": "nospace", 102 | "parameter": "nospace", 103 | "property-declaration": "nospace", 104 | "variable-declaration": "nospace" 105 | } 106 | ], 107 | "typeof-compare": true, 108 | "unified-signatures": true, 109 | "variable-name": false, 110 | "whitespace": [ 111 | true, 112 | "check-branch", 113 | "check-decl", 114 | "check-operator", 115 | "check-separator", 116 | "check-type" 117 | ], 118 | "directive-selector": [ 119 | true, 120 | "attribute", 121 | "app", 122 | "camelCase" 123 | ], 124 | "component-selector": [ 125 | true, 126 | "element", 127 | "app", 128 | "kebab-case" 129 | ], 130 | "use-input-property-decorator": true, 131 | "use-output-property-decorator": true, 132 | "use-host-property-decorator": true, 133 | "no-input-rename": true, 134 | "no-output-rename": true, 135 | "use-life-cycle-interface": true, 136 | "use-pipe-transform-interface": true, 137 | "component-class-suffix": true, 138 | "directive-class-suffix": true, 139 | "invoke-injectable": true 140 | } 141 | } 142 | --------------------------------------------------------------------------------