UNPKG

angular-table-searcher

Version:

This is an angular table searcher. it helps to use keys provided to search through a list of objects and if no keys are provided, it searches for the occurrence of the input value. it also makes request to endpoint if url is provided for backend search.

475 lines (463 loc) 16.4 kB
import { Component, Injectable, Input, NgModule } from '@angular/core'; import { Subject as Subject$1 } from 'rxjs/Subject'; import { Observable as Observable$1 } from 'rxjs/Observable'; import 'rxjs/add/observable/from'; import { ReplaySubject as ReplaySubject$1 } from 'rxjs/ReplaySubject'; import 'rxjs/add/observable/throw'; import { HttpClient, HttpClientModule } from '@angular/common/http'; import { CommonModule } from '@angular/common'; import 'rxjs/add/observable/fromEvent'; import 'rxjs/add/operator/filter'; import 'rxjs/add/operator/debounceTime'; import 'rxjs/add/operator/switch'; import 'rxjs/add/operator/do'; import 'rxjs/add/operator/map'; class EventsService { constructor() { this.listeners = {}; this.eventsSubject = new Subject$1(); this.events = Observable$1.from(this.eventsSubject); this.events.subscribe(({ name, args }) => { if (this.listeners[name]) { for (const listener of this.listeners[name]) { listener(...args); } } }); } /** * @param {?} name * @param {?} listener * @return {?} */ on(name, listener) { if (!this.listeners[name]) { this.listeners[name] = []; this.listeners[name].push(listener); } if (this.listeners[name]) { this.listeners[name][0] = listener; } } /** * @param {?} name * @param {...?} args * @return {?} */ broadcast(name, ...args) { // console.log('name=', name); this.eventsSubject.next({ name, args }); } } EventsService.decorators = [ { type: Injectable }, ]; /** * @nocollapse */ EventsService.ctorParameters = () => []; class TableSearcherService { /** * @param {?} http */ constructor(http$$1) { this.http = http$$1; this.searched = []; } /** * This is used to initialize searching of data from the object passed. * @param {?} values * @param {?=} toFind * @param {?=} keys * @return {?} */ initSearch(values, toFind = '', keys) { this.searched = []; // console.log('keys= ', keys); if (keys && keys.length > 0) { keys.forEach((key) => { // console.log('key=', key); this.startSearching(values, toFind, key); }); } else { this.startSearching(values, toFind); } // console.log('searched=', this.searched); const /** @type {?} */ result = new ReplaySubject$1(); result.next(this.searched); return Observable$1.from(result); // return this.searched; } /** * This is used to start the search after initialization has taken place. * @param {?} values * @param {?} toFind * @param {?=} key * @return {?} */ startSearching(values, toFind, key) { // console.log('values=', values); values.filter((value) => { const /** @type {?} */ status = (key) ? this.processObject(value, toFind, key) : this.processObject(value, toFind); if (status && this.searched.indexOf(value) === -1) { this.searched.push(value); // console.log('Finalsaerched=', status, this.searched); } return status; }); // console.log('ReturnFinalsaerched=', this.searched); } /** * This is used to start an object search for the input values toFind. * @param {?} values * @param {?} toFind * @param {?=} key * @return {?} */ processObject(values, toFind, key) { let /** @type {?} */ status = null; for (const /** @type {?} */ valKey in values) { if (status) { // console.log('this is true'); break; } else { const /** @type {?} */ value = values[valKey]; // console.log('value=', values[valKey], 'KeyVal=', valKey, 'key=', key); if (!value || (key && key !== valKey)) { status = false; continue; } // console.log('key=', valKey, value); switch (value.constructor) { case Array: status = (key) ? this.processArray(value, toFind, [key, valKey]) : this.processArray(value, toFind); // console.log('status1=', status); break; case Object: const /** @type {?} */ innerKeys = Object.keys(value); if (key && innerKeys.indexOf(key) === -1) { status = false; continue; } status = (key) ? this.processObject(value, toFind, key) : this.processObject(value, toFind); // console.log('status2=', status); break; case String: status = (key) ? this.processValidation(value, toFind, [key, valKey]) : this.processValidation(value, toFind); // console.log('status=', status); break; case Number: status = (key) ? this.processValidation(value, toFind, [key, valKey]) : this.processValidation(value, toFind); // console.log('status=', status); break; default: status = false; break; } } } return !!(status); } /** * This is used to filter depth object having multiple level objects or arrays * @param {?} values * @param {?} toFind * @param {?=} keys * @return {?} */ processArray(values, toFind, keys) { values.filter((value) => { if (!value || (keys && keys[0] !== keys[1])) { return false; } switch (value.constructor) { case Array: return !!((keys[0]) ? this.processArray(value, toFind, keys) : this.processArray(value, toFind)); case Object: const /** @type {?} */ innerKeys = Object.keys(value); if (keys[0] && innerKeys.indexOf(keys[0]) === -1) { return false; } return (keys[0]) ? this.processObject(value, toFind, keys[0]) : this.processObject(value, toFind); case String: return (keys[0]) ? this.processValidation(value, toFind, keys) : this.processValidation(value, toFind); case Number: return (keys[0]) ? this.processValidation(value, toFind, keys) : this.processValidation(value, toFind); default: return false; } }); return (values && values.length > 0); } /** * This is used to compare if data lookup is valid or not * @param {?} value * @param {?} toFind * @param {?=} keys * @return {?} */ processValidation(value, toFind, keys) { value = String(value).toLowerCase().trim(); toFind = String(toFind).toLowerCase().trim(); // console.log('toFind=', toFind, 'Value=', value, keys.toString(), (keys[0] === keys[1] && value.indexOf(toFind) > -1)); return (keys) ? (keys[0] === keys[1] && value.indexOf(toFind) > -1) : (value.indexOf(toFind) > -1); } /** * This is used to search backend if empty list is encountered. * @param {?} url * @return {?} */ searchResource(url) { return this.http.get(url); } } TableSearcherService.decorators = [ { type: Injectable }, ]; /** * @nocollapse */ TableSearcherService.ctorParameters = () => [ { type: HttpClient, }, ]; let TableSearcherTypesEnum = {}; TableSearcherTypesEnum.ON_TABLE = 0; TableSearcherTypesEnum.ON_BACKEND = 1; TableSearcherTypesEnum.EMPTY_TABLE_APPLY_BACKEND = 2; TableSearcherTypesEnum[TableSearcherTypesEnum.ON_TABLE] = "ON_TABLE"; TableSearcherTypesEnum[TableSearcherTypesEnum.ON_BACKEND] = "ON_BACKEND"; TableSearcherTypesEnum[TableSearcherTypesEnum.EMPTY_TABLE_APPLY_BACKEND] = "EMPTY_TABLE_APPLY_BACKEND"; class TableSearcherComponent { /** * @param {?} tableSearcherService * @param {?} eventsService */ constructor(tableSearcherService, eventsService) { this.tableSearcherService = tableSearcherService; this.eventsService = eventsService; this.allSettings = { path: null, placeholder: 'What are you looking for?', data: [], searchKeys: [], from: null, queryField: 'search', borderColor: '#eee000', buttonColor: '#83e6bc', searchType: TableSearcherTypesEnum.EMPTY_TABLE_APPLY_BACKEND }; this.searching = false; this.copyData = []; } /** * This is used to set the border color for the div * @return {?} */ setBorderColor() { return { 'border-bottom': '3px solid ' + this.allSettings.borderColor }; } /** * This is used to style the button background * @return {?} */ setButtonColor() { return { 'background': this.allSettings.buttonColor }; } /** * This is used to initialize searching on a table. * @param {?} query * @return {?} */ doSearch(query) { if (!query) { return null; } this.searching = true; setTimeout(() => { switch (this.allSettings.searchType) { case TableSearcherTypesEnum.EMPTY_TABLE_APPLY_BACKEND: this.processSearching(TableSearcherTypesEnum.EMPTY_TABLE_APPLY_BACKEND, query); break; case TableSearcherTypesEnum.ON_BACKEND: this.doSearchBackend(query); break; case TableSearcherTypesEnum.ON_TABLE: this.processSearching(TableSearcherTypesEnum.ON_TABLE, query); break; default: Observable$1.throw('Unknown search type'); break; } }, 200); } /** * This is used to search query strings * @param {?} type * @param {?} query * @return {?} */ processSearching(type, query) { this.tableSearcherService.initSearch(this.allSettings.data, query, this.allSettings.searchKeys) .subscribe((result) => { // console.log('saerchResult=', result); if (result.length === 0 && type === TableSearcherTypesEnum.EMPTY_TABLE_APPLY_BACKEND) { this.doSearchBackend(query); return; } this.eventsService.broadcast(this.allSettings.from, { result: result, data: this.copyData }); this.searching = false; // console.log('searching=', this.searching); }, (err) => { this.searching = false; Observable$1.throw(err); }); } /** * This is used to make a request to a backend api for searching. * @param {?} query * @return {?} */ doSearchBackend(query) { const /** @type {?} */ pos = this.allSettings.path.indexOf('?'); const /** @type {?} */ path = (pos > -1) ? this.allSettings.path + `&${this.allSettings.queryField}=${query}` : this.allSettings.path + `?${this.allSettings.queryField}=${query}`; this.tableSearcherService.searchResource(path) .subscribe((res) => { this.eventsService.broadcast(this.allSettings.from, { result: res, data: this.copyData }); this.searching = false; }, (err) => { this.searching = false; Observable$1.throw(err); }); } /** * This is used to validate object passed down to table searcher. * @return {?} */ ValidateSettings() { for (const /** @type {?} */ key in this.allSettings) { if (!this.allSettings[key]) { this.allSettings[key] = TableSearcherComponent.defaultAllSettings[key]; } } } /** * @return {?} */ ngOnInit() { this.ValidateSettings(); this.copyData = JSON.parse(JSON.stringify(this.allSettings.data)); } } TableSearcherComponent.defaultAllSettings = { path: null, placeholder: 'What are you looking for?', data: [], searchKeys: [], from: null, queryField: 'search', borderColor: '#eee000', buttonColor: '#83e6bc', searchType: TableSearcherTypesEnum.EMPTY_TABLE_APPLY_BACKEND }; TableSearcherComponent.decorators = [ { type: Component, args: [{ selector: 'app-table-searcher', template: ` <div class="table-searcher" [ngStyle]="setBorderColor()" [class.disabled]="searching"> <input [disabled]="searching" (keyup.enter)="doSearch(searchItem.value)" #searchItem type="text" placeholder="{{allSettings.placeholder}}"> <!--<i *ngIf="searching" class="fa fa-spin fa-spinner"></i>--> <button [disabled]="searching" type="button" (click)="doSearch(searchItem.value)" class="button" [ngStyle]="setButtonColor()"> <i *ngIf="searching" class="fa fa-spin fa-spinner"></i> <i class="fa fa-search"></i> </button> </div> <span class="clearOut"></span> `, styles: [` input { width: 80% !important; border: 0 !important; height: 20px !important; padding: 5px !important; } input:visited, input:active, input:link, input:after, input:hover, input:focus, button:focus { border: 0 !important; outline: none; } .table-searcher { border-radius: 5px !important; -moz-border-radius: 5px !important; -webkit-border-radius: 5px !important; width: 100% !important; color: #000; border: 1px solid #ccc; border-bottom: 3px solid #eee000; padding: 0 !important; margin: 0 !important; font-size: 11px !important; } .disabled { background: rgb(235, 235, 228) !important; } .button { background: #83e6bc; padding: 9px !important; color: #fff !important; border: 0 !important; cursor: pointer !important; font-size: 11px; float: right; border-radius: 0 5px 5px 0 !important; -moz-border-radius: 0 5px 5px 0 !important; -webkit-border-radius: 0 5px 5px 0 !important; } .clearOut { clear: both; } `], },] }, ]; /** * @nocollapse */ TableSearcherComponent.ctorParameters = () => [ { type: TableSearcherService, }, { type: EventsService, }, ]; TableSearcherComponent.propDecorators = { 'allSettings': [{ type: Input },], }; class AngularTableSearcherModule { /** * @return {?} */ static forRoot() { return { ngModule: AngularTableSearcherModule, providers: [TableSearcherService, EventsService] }; } } AngularTableSearcherModule.decorators = [ { type: NgModule, args: [{ imports: [ HttpClientModule, CommonModule ], declarations: [TableSearcherComponent], exports: [TableSearcherComponent] },] }, ]; /** * @nocollapse */ AngularTableSearcherModule.ctorParameters = () => []; /** * Generated bundle index. Do not edit. */ export { EventsService, TableSearcherService, TableSearcherTypesEnum, AngularTableSearcherModule, TableSearcherComponent as ɵa }; //# sourceMappingURL=angular-table-searcher.js.map