The answer by Andriy helped me out on a particular problem I was having with the DataTable. We needed a couple of custom filters for >= and <= for floats. I took Andriy's solution and applied it to our problem. I'm posting the code here in case anyone else can benefit from the combined responses.
1 - Built a custom component to handle the input from the user
Typescript:
import { Component, Output, EventEmitter } from '@angular/core';
import { FormBuilder, FormGroup, AbstractControl, FormControl } from '@angular/forms';
import { SelectItem } from 'primeng/components/common/selectitem';
import { ICustomGtLsFilter } from '../../Models/ICustomGtLsFilter';
@Component({
selector: 'app-custom-filter',
templateUrl: './custom-filter.component.html',
styleUrls: ['./custom-filter.component.css']
})
export class CustomFilterComponent {
@Output() onCriteriaSelectedChanged = new EventEmitter<ICustomGtLsFilter>();
_myForm: FormGroup;
_criteria: SelectItem[] = [{label: 'None', value: 'none'}, { label: '<=', value: 'lte' }, { label: '>=', value: 'gte' }];
private _filterModel: ICustomGtLsFilter = new ICustomGtLsFilter();
constructor(private _fb: FormBuilder) {
this._myForm = _fb.group({
_inputField: [null],
_criteriaSel:[]
});
}
fieldChanged(event) {
// clear the input field
if (event === "none") {
this._myForm.controls['_inputField'].setValue('');
}
this._filterModel.Criteria = event;
this._filterModel.FilterVal = this._myForm.controls['_inputField'].value;
this.onCriteriaSelectedChanged.emit(this._filterModel);
}
}
Template
<form [formGroup]="_myForm">
<div class="row">
<div class="col-sm-12">
<input type="number" name="_inputField" id="_inputField" [formControl]="_myForm.controls['_inputField']" autocomplete="off" />
<p-dropdown [options]="_criteria"
[autoWidth]="false"
id="_criteriaSel"
name="_criteriaSel"
placeholder="None"
formControlName="_criteriaSel"
(onChange)="fieldChanged($event.value)">
</p-dropdown>
</div>
</div>
</form>
Interface:
export class ICustomGtLsFilter {
FilterVal: number;
Criteria: string;
}
Here is the custom component defined as an ng-template for the column we want to apply the filter to:
<p-column field='TimeRem'
header='Time Remaining'
[sortable]='true'
[filter]='true'>
<ng-template let-col
pTemplate='filter'>
<app-custom-filter appendTo="body"
(onCriteriaSelectedChanged)="dt.filter($event.FilterVal,col.field,$event.Criteria)">
</app-custom-filter>
</ng-template>
<ng-template let-col
let-rd='rowData'
pTemplate='body'>
<span appAlignRightStyle>{{rd[col.field] | format: '0.0'}}</span>
</ng-template>
</p-column>
And finally the relevant typescript code in the component that uses the DataTable:
...
import { Component, OnInit, OnDestroy, ViewChild, AfterViewInit } from '@angular/core';
import { CustomFilterComponent } from '../../../../shared/custom-filter/custom-filter.component';
import { ICustomGtLsFilter } from '../../../../Models/ICustomGtLsFilter';
export class SomeComponent implements OnInit {
@ViewChild('dt') dt: DataTable;
ngAfterViewInit() {
// custom filter implementations
this.dt.filterConstraints['gte'] = function gte(value: any, filter: any): boolean {
if (filter === undefined || filter === null) {
return false;
}
if (value === undefined || value === null || value.length === 0) {
return false;
}
if (value >= filter) {
return true;
}
return false;
};
this.dt.filterConstraints['lte'] = function lte(value: any, filter: any): boolean {
if (filter === undefined || filter === null) {
return false;
}
if (value === undefined || value === null || value.length === 0) {
return false;
}
if (value <= filter) {
return true;
}
return false;
};
this.dt.filterConstraints['none'] = function none(value: any, filter: any): boolean {
return true;
};
}