<!DOCTYPE html>
<html>
<head>
<title>Angular 4 - PrimeNG Datatable Custom filters</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous" />
<link rel="stylesheet" href="https://unpkg.com/primeng@4.0.0-rc.2/resources/themes/omega/theme.css" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" />
<link rel="stylesheet" href="https://unpkg.com/primeng@4.0.0-rc.2/resources/primeng.min.css" />
<link rel="stylesheet" href="https://unpkg.com/dragula@3.7.2/dist/dragula.css" crossorigin="anonymous" />
</head>
<body>
<my-app>
Loading...
</my-app>
<script src="https://unpkg.com/core-js/client/shim.min.js"></script>
<script src="https://unpkg.com/reflect-metadata@0.1.9/Reflect.js"></script>
<script src="https://unpkg.com/zone.js@0.8.5/dist/zone.js"></script>
<script src="https://unpkg.com/systemjs@0.19.41/dist/system.js"></script>
<script src="https://unpkg.com/typescript@2.2.0/lib/typescript.js"></script>
<script src="config.js"></script>
<script>
System.import('app')
.catch(console.error.bind(console));
</script>
</body>
</html>
/* Styles go here */
System.config({
transpiler: 'typescript',
typescriptOptions: {
emitDecoratorMetadata: true,
experimentalDecorators: true
},
map: {
app: "./src",
'@angular/core': 'npm:@angular/core@4.0.0/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common@4.0.0/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler@4.0.0/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser@4.0.0/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic@4.0.0/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http@4.0.0/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router@4.0.0/bundles/router.umd.js',
'@angular/forms': 'npm:@angular/forms@4.0.0/bundles/forms.umd.js',
'@angular/animations': 'npm:@angular/animations@4.0.0/bundles/animations.umd.js',
'@angular/core/testing': 'npm:@angular/core@4.0.0/bundles/core-testing.umd.js',
'@angular/common/testing': 'npm:@angular/common/bundles@4.0.0/common-testing.umd.js',
'@angular/compiler/testing': 'npm:@angular/compiler@4.0.0/bundles/compiler-testing.umd.js',
'@angular/platform-browser/testing': 'npm:@angular/platform-browser@4.0.0/bundles/platform-browser-testing.umd.js',
'@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic@4.0.0/bundles/platform-browser-dynamic-testing.umd.js',
'@angular/http/testing': 'npm:@angular/http@4.0.0/bundles/http-testing.umd.js',
'@angular/router/testing': 'npm:@angular/router@4.0.0/bundles/router-testing.umd.js',
'rxjs': 'npm:rxjs@5.1.0',
'lodash': 'npm:lodash@4.17.4/',
'primeng': 'npm:primeng@4.1.2/primeng.js'
},
//packages defines our app package
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
},
rxjs: {
defaultExtension: 'js'
},
lodash: {
defaultExtension: 'js'
},
primeng: {
defaultExtension: 'js'
}
},
paths: {
'npm:': 'https://unpkg.com/'
}
});
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { DataTableModule,
SharedModule,
MultiSelectModule,
OverlayPanelModule
} from 'primeng';
@NgModule({
imports: [
BrowserModule, CommonModule, FormsModule, DataTableModule,
SharedModule,
MultiSelectModule,
OverlayPanelModule
],
declarations: [
AppComponent
],
providers: []
bootstrap: [ AppComponent ]
})
export class AppModule {}
{
"compilerOptions": {
"baseUrl": "",
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es6", "dom"],
"mapRoot": "./",
"module": "es6",
"moduleResolution": "node",
"sourceMap": true,
"target": "es5"
}
}
//our root app component
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import {ROUTER_PROVIDERS, ROUTER_DIRECTIVES, RouteParams, RouteConfig, Router, LocationStrategy, HashLocationStrategy} from '@angular2/router';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
import { Component, Input, Output, AfterViewInit, ElementRef, EventEmitter, OnChanges } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: 'src/app.component.html',
styleUrls: ['src/app.css']
})
export class AppComponent implements OnInit {
public visible: boolean = true;
public filtered: Map<string, boolean> = new Map<string, boolean>();
public filter = {
person: [],
planet: []
};
public data = [
{
planet: 'Tatooine',
person: 'Luke Skywalker'
},{
planet: 'Tatooine',
person: 'Obi-wan Kenobi'
},{
planet: 'Alderaan',
person: 'Leia Organa'
},{
planet: 'Degobah',
person: 'Master Yoda'
}
];
public people = [
{
label: 'Luke Skywalker',
value: 1
},{
label: 'Obi-wan Kenobi',
value: 2
},{
label: 'Leia Organa',
value: 3
},{
label: 'Master Yoda',
value: 4
}];
public planets = [
{
label: 'Tatooine',
value: 1
},{
label: 'Alderaan',
value: 2
},{
label: 'Degobah',
value:3
}];
constructor() {
}
ngOnInit() {
}
updateFilters($event) {
this.filters = [];
this.filtered = new Map<string, boolean>();
for (const prop in this.filter) {
if (this.filter.hasOwnProperty(prop)) {
this.filtered[prop] = this.filter[prop].length;
if (this.filter[prop].length) {
console.log(prop);
}
}
}
}
}
<div class="header">
<h2>Angular 4 - PrimeNG Datatable Custom Filters</h2>
</div>
<div class="container-fluid" style="padding-top:20px;">
<div class="row">
<div class="col-md-12">
<p-dataTable [value]="data">
<p-column field="person" header="Person" [filter]="true">
<ng-template #personFilterTemplate pTemplate="filter" let-col>
<i class="fa fa-filter" (click)="personMenu.toggle($event)" *ngIf="!filtered[col.field]"></i>
<span class="fa-stack" (click)="personMenu.toggle($event)" *ngIf="filtered[col.field]">
<i class="fa fa-square fa-stack-2x"></i>
<i class="fa fa-filter fa-stack-1x fa-inverse"></i>
</span>
</ng-template>
</p-column>
<p-column field="planet" header="Planet" [filter]="true">
<ng-template #planetFilterTemplate pTemplate="filter" let-col>
<i class="fa fa-filter" (click)="planetMenu.toggle($event)" *ngIf="!filtered[col.field]"></i>
<span class="fa-stack" (click)="planetMenu.toggle($event)" *ngIf="filtered[col.field]">
<i class="fa fa-square fa-stack-2x"></i>
<i class="fa fa-filter fa-stack-1x fa-inverse"></i>
</span>
</ng-template>
</p-column>
</p-dataTable>
</div>
</div>
</div>
<p-overlayPanel #personMenu showCloseIcon="true">
<p-multiSelect [overlayVisible]="visible" [options]="people" filter="true" defaultLabel="This is a demo" (onChange)="updateFilters($event)" [(ngModel)]="filter.person"></p-multiSelect>
</p-overlayPanel>
<p-overlayPanel #planetMenu showCloseIcon="true">
<p-multiSelect [overlayVisible]="visible" [options]="planets" filter="true" defaultLabel=" " (onChange)="updateFilters($event)" [(ngModel)]="filter.planet"></p-multiSelect>
</p-overlayPanel>
<HR />
<p-multiSelect [overlayVisible]="visible" [options]="people" filter="true" defaultLabel="This is a demo"></p-multiSelect>
import { Directive, OnChanges, AfterViewInit, OnInit, Input, ElementRef, SimpleChange } from '@angular/core';
import { DragulaService, dragula } from 'ng2-dragula';
@Directive({ selector: '[primeDragula]' })
export class PrimeDragulaDirective implements OnChanges, OnInit, AfterViewInit {
@Input() public primeDragula: string;
@Input() public dragulaModel: any;
@Input() public dragulaOptions: any;
protected container: any;
private drake: any;
private options: any;
private el: ElementRef;
private dragulaService: DragulaService;
public constructor(el: ElementRef, dragulaService: DragulaService) {
this.el = el;
this.dragulaService = dragulaService;
}
ngOnInit(){
this.options = Object.assign({}, this.dragulaOptions);
this.container = this.el.nativeElement;
if(!this.options.initAfterView){
this.initialize();
}
}
ngAfterViewInit() {
if(this.options.initAfterView){
this.initialize();
}
}
//since we dont have access to the ngprime datatable body or table itself we need to bing laters in the angular event cycle
//Once this fires we have a tbody tag to attach to and create the drag drop area from.
//because we need to setup dragula later we needed to create our own version of the directive so we have access to the private property container.
//If ngdragula ever changes that to protected we can just extend that directive outright and override the container.
protected initialize(){
if(this.options.childContainerSelector){
this.container = this.el.nativeElement.querySelector(this.options.childContainerSelector);
this.options.mirrorContainer = this.container;
}
let bag = this.dragulaService.find(this.primeDragula);
let checkModel = () => {
if (this.dragulaModel) {
if (this.drake.models) {
this.drake.models.push(this.dragulaModel);
} else {
this.drake.models = [this.dragulaModel];
}
}
};
if (bag) {
this.drake = bag.drake;
checkModel();
this.drake.containers.push(this.container);
} else {
this.drake = dragula([this.container], this.options);
checkModel();
this.dragulaService.add(this.primeDragula, this.drake);
}
}
public ngOnChanges(changes: { dragulaModel?: SimpleChange }): void {
if (changes && changes.dragulaModel) {
if (this.drake) {
if (this.drake.models) {
let modelIndex = this.drake.models.indexOf(changes.dragulaModel.previousValue);
this.drake.models.splice(modelIndex, 1, changes.dragulaModel.currentValue);
} else {
this.drake.models = [changes.dragulaModel.currentValue];
}
}
}
}
}