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.
434 lines (433 loc) • 18.1 kB
JavaScript
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';
var EventsService = (function () {
function EventsService() {
var _this = this;
this.listeners = {};
this.eventsSubject = new Subject$1();
this.events = Observable$1.from(this.eventsSubject);
this.events.subscribe(function (_a) {
var name = _a.name, args = _a.args;
if (_this.listeners[name]) {
for (var _i = 0, _b = _this.listeners[name]; _i < _b.length; _i++) {
var listener = _b[_i];
listener.apply(void 0, args);
}
}
});
}
/**
* @param {?} name
* @param {?} listener
* @return {?}
*/
EventsService.prototype.on = function (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 {?}
*/
EventsService.prototype.broadcast = function (name) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
// console.log('name=', name);
this.eventsSubject.next({
name: name,
args: args
});
};
return EventsService;
}());
EventsService.decorators = [
{ type: Injectable },
];
/**
* @nocollapse
*/
EventsService.ctorParameters = function () { return []; };
var TableSearcherService = (function () {
/**
* @param {?} http
*/
function TableSearcherService(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 {?}
*/
TableSearcherService.prototype.initSearch = function (values, toFind, keys) {
var _this = this;
if (toFind === void 0) { toFind = ''; }
this.searched = [];
// console.log('keys= ', keys);
if (keys && keys.length > 0) {
keys.forEach(function (key) {
// console.log('key=', key);
_this.startSearching(values, toFind, key);
});
}
else {
this.startSearching(values, toFind);
}
// console.log('searched=', this.searched);
var /** @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 {?}
*/
TableSearcherService.prototype.startSearching = function (values, toFind, key) {
var _this = this;
// console.log('values=', values);
values.filter(function (value) {
var /** @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 {?}
*/
TableSearcherService.prototype.processObject = function (values, toFind, key) {
var /** @type {?} */ status = null;
for (var /** @type {?} */ valKey in values) {
if (status) {
// console.log('this is true');
break;
}
else {
var /** @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:
var /** @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 {?}
*/
TableSearcherService.prototype.processArray = function (values, toFind, keys) {
var _this = this;
values.filter(function (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:
var /** @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 {?}
*/
TableSearcherService.prototype.processValidation = function (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 {?}
*/
TableSearcherService.prototype.searchResource = function (url) {
return this.http.get(url);
};
return TableSearcherService;
}());
TableSearcherService.decorators = [
{ type: Injectable },
];
/**
* @nocollapse
*/
TableSearcherService.ctorParameters = function () { return [
{ type: HttpClient, },
]; };
var 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";
var TableSearcherComponent = (function () {
/**
* @param {?} tableSearcherService
* @param {?} eventsService
*/
function TableSearcherComponent(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 {?}
*/
TableSearcherComponent.prototype.setBorderColor = function () {
return { 'border-bottom': '3px solid ' + this.allSettings.borderColor };
};
/**
* This is used to style the button background
* @return {?}
*/
TableSearcherComponent.prototype.setButtonColor = function () {
return { 'background': this.allSettings.buttonColor };
};
/**
* This is used to initialize searching on a table.
* @param {?} query
* @return {?}
*/
TableSearcherComponent.prototype.doSearch = function (query) {
var _this = this;
if (!query) {
return null;
}
this.searching = true;
setTimeout(function () {
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 {?}
*/
TableSearcherComponent.prototype.processSearching = function (type, query) {
var _this = this;
this.tableSearcherService.initSearch(this.allSettings.data, query, this.allSettings.searchKeys)
.subscribe(function (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);
}, function (err) {
_this.searching = false;
Observable$1.throw(err);
});
};
/**
* This is used to make a request to a backend api for searching.
* @param {?} query
* @return {?}
*/
TableSearcherComponent.prototype.doSearchBackend = function (query) {
var _this = this;
var /** @type {?} */ pos = this.allSettings.path.indexOf('?');
var /** @type {?} */ path = (pos > -1) ? this.allSettings.path + ("&" + this.allSettings.queryField + "=" + query) : this.allSettings.path + ("?" + this.allSettings.queryField + "=" + query);
this.tableSearcherService.searchResource(path)
.subscribe(function (res) {
_this.eventsService.broadcast(_this.allSettings.from, { result: res, data: _this.copyData });
_this.searching = false;
}, function (err) {
_this.searching = false;
Observable$1.throw(err);
});
};
/**
* This is used to validate object passed down to table searcher.
* @return {?}
*/
TableSearcherComponent.prototype.ValidateSettings = function () {
for (var /** @type {?} */ key in this.allSettings) {
if (!this.allSettings[key]) {
this.allSettings[key] = TableSearcherComponent.defaultAllSettings[key];
}
}
};
/**
* @return {?}
*/
TableSearcherComponent.prototype.ngOnInit = function () {
this.ValidateSettings();
this.copyData = JSON.parse(JSON.stringify(this.allSettings.data));
};
return TableSearcherComponent;
}());
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: "\n <div class=\"table-searcher\" [ngStyle]=\"setBorderColor()\" [class.disabled]=\"searching\">\n <input [disabled]=\"searching\" (keyup.enter)=\"doSearch(searchItem.value)\" #searchItem type=\"text\" placeholder=\"{{allSettings.placeholder}}\">\n <!--<i *ngIf=\"searching\" class=\"fa fa-spin fa-spinner\"></i>-->\n <button [disabled]=\"searching\" type=\"button\" (click)=\"doSearch(searchItem.value)\" class=\"button\" [ngStyle]=\"setButtonColor()\">\n <i *ngIf=\"searching\" class=\"fa fa-spin fa-spinner\"></i> <i class=\"fa fa-search\"></i>\n </button>\n </div>\n <span class=\"clearOut\"></span>\n ",
styles: ["\n input {\n width: 80% !important;\n border: 0 !important;\n height: 20px !important;\n padding: 5px !important;\n }\n\n input:visited, input:active, input:link, input:after, input:hover, input:focus, button:focus {\n border: 0 !important;\n outline: none;\n }\n\n .table-searcher {\n border-radius: 5px !important;\n -moz-border-radius: 5px !important;\n -webkit-border-radius: 5px !important;\n width: 100% !important;\n color: #000;\n border: 1px solid #ccc;\n border-bottom: 3px solid #eee000;\n padding: 0 !important;\n margin: 0 !important;\n font-size: 11px !important;\n }\n\n .disabled {\n background: rgb(235, 235, 228) !important;\n }\n\n .button {\n background: #83e6bc;\n padding: 9px !important;\n color: #fff !important;\n border: 0 !important;\n cursor: pointer !important;\n font-size: 11px;\n float: right;\n border-radius: 0 5px 5px 0 !important;\n -moz-border-radius: 0 5px 5px 0 !important;\n -webkit-border-radius: 0 5px 5px 0 !important;\n }\n .clearOut {\n clear: both;\n }\n "],
},] },
];
/**
* @nocollapse
*/
TableSearcherComponent.ctorParameters = function () { return [
{ type: TableSearcherService, },
{ type: EventsService, },
]; };
TableSearcherComponent.propDecorators = {
'allSettings': [{ type: Input },],
};
var AngularTableSearcherModule = (function () {
function AngularTableSearcherModule() {
}
/**
* @return {?}
*/
AngularTableSearcherModule.forRoot = function () {
return {
ngModule: AngularTableSearcherModule,
providers: [TableSearcherService, EventsService]
};
};
return AngularTableSearcherModule;
}());
AngularTableSearcherModule.decorators = [
{ type: NgModule, args: [{
imports: [
HttpClientModule,
CommonModule
],
declarations: [TableSearcherComponent],
exports: [TableSearcherComponent]
},] },
];
/**
* @nocollapse
*/
AngularTableSearcherModule.ctorParameters = function () { return []; };
/**
* Generated bundle index. Do not edit.
*/
export { EventsService, TableSearcherService, TableSearcherTypesEnum, AngularTableSearcherModule, TableSearcherComponent as ɵa };
//# sourceMappingURL=angular-table-searcher.es5.js.map