UNPKG

ngx-magicsearch

Version:

Magic Search/Faceted Search Library for Angular 2.

911 lines (903 loc) 32 kB
import { KeyValueDiffers, HostListener, Output, Component, Input, EventEmitter, Injectable, PLATFORM_ID, Inject, Directive, ElementRef, NgModule } from '@angular/core'; import { isPlatformBrowser, CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class NgxMagicSearchComponent { /** * @param {?} differs */ constructor(differs) { this.differs = differs; this.strings = { remove: 'Remove facet', cancel: 'Clear search', prompt: 'Select facets or enter text', 'text': 'Text' }; this.facets_param = []; /*Array<{name: string, label: string, options: Array<{key: string, label: string}>}>|string*/ this.textSearchEvent = new EventEmitter(); this.searchUpdatedEvent = new EventEmitter(); this.setFocusedEventEmitter = false; this.promptString = this.strings.prompt; this.currentSearch = []; this.facetsObj = null; this.isMenuOpen = false; this.hostEvent = null; this.differ = differs.find({}).create(); this.searchInput = ''; } /** * @return {?} */ ngOnInit() { this.initSearch(); } /** * @return {?} */ ngOnChanges() { this.initSearch(); } /** * @return {?} */ ngDoCheck() { const /** @type {?} */ changes = this.differ.diff(this.facets_param); if (changes) { this.initSearch(); } } /** * * * * \@memberOf NgxMagicSearchComponent * @return {?} */ initSearch() { if (typeof this.facets_param === 'string') { // Parse facets JSON and convert to a list of facets. const /** @type {?} */ tmp = this.facets_param.replace(/__apos__/g, '\'').replace(/__dquote__/g, '\\"').replace(/__bslash__/g, '\\'); this.facetsObj = JSON.parse(tmp); } else { // Assume this is a usable javascript object this.facetsObj = this.facets_param.slice(0); } this.facetsSave = this.copyFacets(this.facetsObj); this.currentSearch = []; this.initFacets(); } /** * * * * \@memberOf NgxMagicSearchComponent * @return {?} */ initFacets() { const /** @type {?} */ that = this; // set facets selected and remove them from facetsObj let /** @type {?} */ initialFacets = (window.location.hash.split('?')[1] === undefined) ? '' : '?' + window.location.hash.split('?')[1]; if (initialFacets.length < 1) { for (let /** @type {?} */ i = 0; i < this.currentSearch.length; i++) { if (this.currentSearch[i].name.indexOf('text') !== 0) { if (initialFacets.length > 0) { initialFacets = initialFacets + '&'; } initialFacets = initialFacets + this.currentSearch[i].name; } } this.facetsObj = this.copyFacets(this.facetsSave); this.currentSearch = []; } if (initialFacets.indexOf('?') === 0) { initialFacets = initialFacets.slice(1); } initialFacets = initialFacets.split('&'); if (initialFacets.length > 1 || initialFacets[0].length > 0) { setTimeout(() => { this.strings.prompt = ''; }, 0.1); } initialFacets.forEach(function (facet, idx) { const /** @type {?} */ facetParts = facet.split('='); facetParts[1] = facet.split('=').splice(1).join('='); that.facetsObj.forEach(function (value, idx_value) { if (value.name === facetParts[0]) { if (value.options === undefined) { that.currentSearch.push({ 'name': facet, 'label': [value.label, facetParts[1]] }); // allow free-form facets to remain } else { value.options.forEach(function (option, idx_option) { if (option.key === facetParts[1]) { that.currentSearch.push({ 'name': facet, 'label': [value.label, option.label] }); if (value.singleton === true) { that.deleteFacetEntirely(facetParts); } else { that.deleteFacetSelection(facetParts); } } }); } } }); }); if (this.textSearch !== undefined) { this.currentSearch.push({ 'name': 'text=' + this.textSearch, 'label': [this.strings.text, this.textSearch] }); } this.filteredObj = this.facetsObj; } /** * add a facets javascript object to the existing list * * \@memberOf NgxMagicSearchComponent * @param {?} facets * * @return {?} */ addFacets(facets) { const /** @type {?} */ that = this; facets.forEach(function (facet) { that.facetsObj.append(facet); }); } /** * * * \@memberOf NgxMagicSearchComponent * @param {?} facets * @return {?} * */ copyFacets(facets) { const /** @type {?} */ ret = []; for (let /** @type {?} */ i = 0; i < facets.length; i++) { const /** @type {?} */ facet = Object.create(facets[i]); if (facets[i].options !== undefined) { facet.options = []; for (let /** @type {?} */ j = 0; j < facets[i].options.length; j++) { facet.options.push(Object.create(facets[i].options[j])); } } ret.push(facet); } return ret; } /** * * * \@memberOf NgxMagicSearchComponent * @param {?} facetParts * * @return {?} */ deleteFacetSelection(facetParts) { const /** @type {?} */ that = this; this.facetsObj.slice().forEach(function (facet, idx) { if (facet.name === facetParts[0]) { if (facet.options === undefined) { return; // allow free-form facets to remain } for (let /** @type {?} */ i = 0; i < facet.options.length; i++) { const /** @type {?} */ option = facet.options[i]; if (option.key === facetParts[1]) { that.facetsObj[idx].options.splice(that.facetsObj[idx].options.indexOf(option), 1); } } if (facet.options.length === 0) { that.facetsObj.splice(that.facetsObj.indexOf(facet), 1); } } }); } /** * remove entire facet * * \@memberOf NgxMagicSearchComponent * @param {?} facetParts * * @return {?} */ deleteFacetEntirely(facetParts) { const /** @type {?} */ that = this; this.facetsObj.slice().forEach(function (facet, idx) { if (facet.name === facetParts[0]) { that.facetsObj.splice(that.facetsObj.indexOf(facet), 1); } }); } /** * try filtering facets/options.. if no facets match, do text search * * \@memberOf NgxMagicSearchComponent * @param {?} searchVal * @return {?} * */ filterFacets(searchVal) { let /** @type {?} */ i, /** @type {?} */ idx, /** @type {?} */ label; const /** @type {?} */ filtered = []; if (this.facetSelected === undefined) { this.filteredObj = this.facetsObj; for (i = 0; i < this.filteredObj.length; i++) { const /** @type {?} */ facet = this.filteredObj[i]; idx = facet.label.toLowerCase().indexOf(searchVal); if (idx > -1) { label = [ facet.label.substring(0, idx), facet.label.substring(idx, idx + searchVal.length), facet.label.substring(idx + searchVal.length) ]; filtered.push({ 'name': facet.name, 'label': label, 'options': facet.options }); } } if (filtered.length > 0) { this.showMenu(); setTimeout(() => { this.filteredObj = filtered; }, 0.1); } else { this.textSearchEvent.emit(searchVal); this.hideMenu(); } } else { // assume option search this.filteredOptions = this.facetOptions; if (this.facetOptions === undefined) { // no options, assume free form text facet return; } for (i = 0; i < this.filteredOptions.length; i++) { const /** @type {?} */ option = this.filteredOptions[i]; idx = option.label.toLowerCase().indexOf(searchVal); if (idx > -1) { label = [ option.label.substring(0, idx), option.label.substring(idx, idx + searchVal.length), option.label.substring(idx + searchVal.length) ]; filtered.push({ 'key': option.key, 'label': label }); } } if (filtered.length > 0) { this.showMenu(); setTimeout(() => { this.filteredOptions = filtered; }, 0.1); } } } /** * * * \@memberOf NgxMagicSearchComponent * @param {?} label * @return {?} * */ isMatchLabel(label) { return Array.isArray(label); } /** * * * * \@memberOf NgxMagicSearchComponent * @return {?} */ resetState() { this.updateUrl(''); this.searchInput = ''; this.filteredObj = this.facetsObj; this.facetSelected = undefined; this.facetOptions = undefined; this.filteredOptions = undefined; if (this.currentSearch.length === 0) { this.strings.prompt = this.promptString; } } /** * showMenu and hideMenu depend on foundation's dropdown. They need * to be modified to work with another dropdown implemenation (i.e. bootstrap) * * * \@memberOf NgxMagicSearchComponent * @return {?} */ showMenu() { this.isMenuOpen = true; } /** * hide dropdown * * * \@memberOf NgxMagicSearchComponent * @return {?} */ hideMenu() { this.isMenuOpen = false; } /** * * * \@memberOf NgxMagicSearchComponent * @param {?} query * * @return {?} */ updateUrl(query) { let /** @type {?} */ url = window.location.href; if (url.indexOf('?') > -1) { url = url.split('?')[0]; } if (query.length > 0) { url = url + '?' + query; } window.history.pushState(query, '', url); } /** * * * \@memberOf NgxMagicSearchComponent * @return {?} * */ buildTermsArray() { const /** @type {?} */ that = this; const /** @type {?} */ returnArray = []; this.currentSearch.forEach(function (item) { const /** @type {?} */ explode = item.name.split('='); explode[1] = item.name.split('=').splice(1).join('='); if (that.getIndexBy(returnArray, 'key', explode[0]) !== -1) { returnArray[that.getIndexBy(returnArray, 'key', explode[0])].values.push(explode[1]); } else { returnArray.push({ key: explode[0], values: [explode[1]] }); } }); return returnArray; } /** * * * \@memberOf NgxMagicSearchComponent * @param {?} array * @param {?} key_name * @param {?} value * @return {?} * */ getIndexBy(array, key_name, value) { for (let /** @type {?} */ i = 0; i < array.length; i++) { if (array[i][key_name] === value) { return i; } } return -1; } /** * * * \@memberOf NgxMagicSearchComponent * @param {?} event * * @return {?} */ handleKeyDown(event) { const /** @type {?} */ key = event.keyCode || event.charCode; if (key === 9) { // prevent default when we can. event.preventDefault(); } } /** * * * \@memberOf NgxMagicSearchComponent * @param {?} event * @return {?} * */ handleKeyUp(event) { // handle ctrl-char input if (event.metaKey === true) { return; } const /** @type {?} */ searchVal = this.searchInput; const /** @type {?} */ key = event.keyCode || event.charCode; if (key === 9) { // tab, so select facet if narrowed down to 1 if (this.facetSelected === undefined) { if (this.filteredObj.length !== 1) { return; } this.facetClicked(0, this.filteredObj[0].name); } else { if (this.filteredOptions === undefined || this.filteredOptions.length !== 1) { return; } this.optionClicked(0, this.filteredOptions[0].key); this.resetState(); } setTimeout(() => { this.searchInput = ''; }, 0.1); return; } if (key === 27) { // esc, so cancel and reset everthing setTimeout(() => { this.hideMenu(); this.searchInput = ''; }, 0.1); this.resetState(); let /** @type {?} */ textFilter = this.textSearch; if (textFilter === undefined) { textFilter = ''; } this.textSearchEvent.emit(searchVal); return; } if (key === 13) { // enter, so accept value // if tag search, treat as regular facet if (this.facetSelected && this.facetSelected.options === undefined) { const /** @type {?} */ curr = this.facetSelected; curr.name = curr.name + '=' + searchVal; curr.label[1] = searchVal; this.currentSearch.push(curr); this.resetState(); this.emitQuery(); this.showMenu(); } else { // if text search treat as search for (let /** @type {?} */ i = 0; i < this.currentSearch.length; i++) { if (this.currentSearch[i].name.indexOf('text') === 0) { this.currentSearch.splice(i, 1); } } this.currentSearch.push({ 'name': 'text=' + searchVal, 'label': [this.strings.text, searchVal] }); this.hideMenu(); this.searchInput = ''; this.textSearchEvent.emit(searchVal); this.textSearch = searchVal; } this.filteredObj = this.facetsObj; } else { if (searchVal === '') { this.filteredObj = this.facetsObj; this.textSearchEvent.emit(''); if (this.facetSelected && this.facetSelected.options === undefined) { this.resetState(); } } else { this.filterFacets(searchVal); } } } /** * * * \@memberOf NgxMagicSearchComponent * @param {?} event * @return {?} * */ handleKeyPress(event) { // handle character input let /** @type {?} */ searchVal = this.searchInput; const /** @type {?} */ key = event.which || event.keyCode || event.charCode; if (key !== 8 && key !== 46 && key !== 13 && key !== 9 && key !== 27) { searchVal = searchVal + String.fromCharCode(key).toLowerCase(); } if (searchVal === ' ') { // space and field is empty, show menu this.showMenu(); setTimeout(() => { this.searchInput = ''; }, 0.1); return; } if (searchVal === '') { this.filteredObj = this.facetsObj; this.textSearchEvent.emit(''); if (this.facetSelected && this.facetSelected.options === undefined) { this.resetState(); } return; } if (key !== 8 && key !== 46) { this.filterFacets(searchVal); } } /** * enable text entry when mouse clicked anywhere in search box * * * \@memberOf NgxMagicSearchComponent * @return {?} */ enableTextEntry() { this.setFocusedEventEmitter = true; this.showMenu(); } /** * when facet clicked, add 1st part of facet and set up options * * \@memberOf NgxMagicSearchComponent * @param {?} index * @param {?} name * * @return {?} */ facetClicked(index, name) { this.hideMenu(); const /** @type {?} */ facet = this.filteredObj[index]; let /** @type {?} */ label = facet.label; if (Array.isArray(label)) { label = label.join(''); } this.facetSelected = { 'name': facet.name, 'label': [label, ''] }; if (facet.options !== undefined) { this.filteredOptions = this.facetOptions = facet.options; this.showMenu(); } setTimeout(() => { this.searchInput = ''; }, 0.1); this.strings.prompt = ''; setTimeout(() => { this.setFocusedEventEmitter = true; }, 0.1); } /** * when option clicked, complete facet and send event * * \@memberOf NgxMagicSearchComponent * @param {?} index * @param {?} name * * @return {?} */ optionClicked(index, name) { const /** @type {?} */ curr = this.facetSelected; curr.name = curr.name + '=' + name; curr.label[1] = this.filteredOptions[index].label; if (Array.isArray(curr.label[1])) { curr.label[1] = curr.label[1].join(''); } this.currentSearch.push(curr); this.resetState(); this.emitQuery(); setTimeout(() => { this.hideMenu(); }, 0.1); } /** * * * \@memberOf NgxMagicSearchComponent * @param {?} category * @param {?} option * * @return {?} */ addFilterManually(category, option) { const /** @type {?} */ indexCategory = this.filteredObj.findIndex(categoryElement => categoryElement.name === category); const /** @type {?} */ indexOption = (indexCategory !== -1) ? this.filteredObj[indexCategory].options.findIndex(optionElement => optionElement.key === option) : -1; if (indexCategory !== -1 && indexOption !== -1) { this.facetClicked(indexCategory, category); this.optionClicked(indexOption, option); } } /** * * * \@memberOf NgxMagicSearchComponent * @param {?} category * @param {?} option * * @return {?} */ removeFilterManually(category, option) { const /** @type {?} */ indexSearch = this.currentSearch.findIndex(searchElement => searchElement.name === category + '=' + option); if (indexSearch !== -1) { this.removeFacet(indexSearch); } } /** * send event with new query string * * \@memberOf NgxMagicSearchComponent * @param {?=} removed * * @return {?} */ emitQuery(removed) { const /** @type {?} */ that = this; let /** @type {?} */ query = ''; for (let /** @type {?} */ i = 0; i < this.currentSearch.length; i++) { if (this.currentSearch[i].name.indexOf('text') !== 0) { if (query.length > 0) { query = query + '&'; } query = query + this.currentSearch[i].name; } } if (removed !== undefined && removed.indexOf('text') === 0) { this.textSearchEvent.emit(''); this.textSearch = undefined; } else { this.searchUpdatedEvent.emit(this.buildTermsArray()); this.updateUrl(query); if (this.currentSearch.length > 0) { // prune facets as needed from menus const /** @type {?} */ newFacet = this.currentSearch[this.currentSearch.length - 1].name; const /** @type {?} */ facetParts = newFacet.split('='); this.facetsSave.forEach(function (facet, idx) { if (facet.name === facetParts[0]) { if (facet.singleton === true) { that.deleteFacetEntirely(facetParts); } else { that.deleteFacetSelection(facetParts); } } }); } } } /** * remove facet and either update filter or search * * \@memberOf NgxMagicSearchComponent * @param {?} index * * @return {?} */ removeFacet(index) { const /** @type {?} */ removed = this.currentSearch[index].name; this.currentSearch.splice(index, 1); if (this.facetSelected === undefined) { this.emitQuery(removed); } else { this.resetState(); this.searchInput = ''; } if (this.currentSearch.length === 0) { this.strings.prompt = this.promptString; } // re-init to restore facets cleanly this.facetsObj = this.copyFacets(this.facetsSave); this.initFacets(); } /** * clear entire searchbar * * * \@memberOf NgxMagicSearchComponent * @return {?} */ clearSearch() { if (this.currentSearch.length > 0) { this.currentSearch = []; this.facetsObj = this.copyFacets(this.facetsSave); this.resetState(); this.searchUpdatedEvent.emit(null); this.textSearchEvent.emit(''); } } /** * Catch click outside of the component * @param {?} globalEvent * @return {?} */ compareEvent(globalEvent) { // If the last known host event and the given global event are // the same reference, we know that the event originated within // the host (and then bubbled up out of the host and eventually // hit the global binding). As such, it can't be an "outside" // event and therefore we should ignore it. if (this.hostEvent === globalEvent) { return; } // Now that we know the event was initiated outside of the host, // we can emit the output event. By convention above, we know // that we can simply use the event type to reference the // correct output event stream. this.hideMenu(); } /** * @param {?} newHostEvent * @return {?} */ trackEvent(newHostEvent) { this.hostEvent = newHostEvent; } } NgxMagicSearchComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-magic-search', template: `<div class="magic-search"> <div class="search-bar"> <i class="fa fa-filter go"></i> <div class="search-main-area" (click)="enableTextEntry()"> <span class="item-list" *ngIf="currentSearch"> <span *ngFor="let facet of currentSearch; let i = index;" class="ngx-label radius secondary item"> <span>{{ facet.label[0] }}:<b>{{ facet.label[1] }}</b></span> <a class="remove" (click)="removeFacet(i)" title="{{ strings.remove }}"><i class="fa fa-times"></i></a> </span> </span> <span class="search-selected ngx-label" *ngIf="facetSelected"> {{ facetSelected.label[0] }}: </span> <!-- For bootstrap, the dropdown attribute is moved from input up to div. --> <div [ngClass]="{'search-entry': true, 'dropdown': true, 'active': isMenuOpen}"> <input class="search-input" type="text" placeholder="{{ strings.prompt }}" autocomplete="off" (keyup)="handleKeyUp($event)" (keydown)="handleKeyDown($event)" (keypress)="handleKeyPress($event)" [(ngModel)]="searchInput" ngxMagicSearch="setFocusedEventEmitter" /> <div class="dropdown-content" *ngIf="filteredObj.length > 0"> <div class="arrow-up"></div> <ul class="ngx-dropdown-menu"> <ng-template [ngIf]="!facetSelected"> <li *ngFor="let facet of filteredObj; let i = index;"> <a (click)="facetClicked(i, facet.name)" *ngIf="!isMatchLabel(facet.label)">{{ facet.label }}</a> <a (click)="facetClicked(i, facet.name)" *ngIf="isMatchLabel(facet.label)"> {{ facet.label[0] }}<span class="match">{{ facet.label[1] }}</span>{{ facet.label[2] }} </a> </li> </ng-template> <ng-template [ngIf]="facetSelected"> <li *ngFor="let option of filteredOptions; let i = index;"> <a (click)="optionClicked(i, option.key)" *ngIf="!isMatchLabel(option.label)"> {{ option.label }} </a> <a (click)="optionClicked(i, option.key)" *ngIf="isMatchLabel(option.label)"> {{ option.label[0] }}<span class="match">{{ option.label[1] }}</span>{{ option.label[2] }} </a> </li> </ng-template> </ul> </div> </div> </div> <a (click)="clearSearch()" *ngIf="currentSearch.length > 0" title="{{ strings.cancel }}"> <i class="fa fa-times cancel"></i> </a> </div> </div>`, styles: [`.dropdown{position:relative;display:inline-block}.dropdown-content{display:none;position:absolute;min-width:160px;z-index:1;margin-top:4px}.dropdown.active .dropdown-content{display:block}.ngx-dropdown-menu{z-index:1000;min-width:160px;padding:5px 0;margin:0;font-size:14px;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border-radius:3px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.ngx-dropdown-menu li:hover{cursor:pointer;background-color:#eaeaea}.arrow-up{width:0;height:0;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #fff;margin-left:5px}.ngx-dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.ngx-label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}@-moz-document url-prefix(){.item-list .item,.search-selected{top:-.4rem}}.search-bar{font-size:14px;position:relative;border:1px solid #ccc;background-color:#fff;height:auto}.search-bar i.fa-filter{color:#6a737b;position:absolute;top:.75rem;left:.65rem;font-size:18px}.search-bar .search-main-area{position:relative;margin-left:2.75rem;margin-right:2.75rem;cursor:text;text-align:left}.search-bar .item-list{position:relative;margin-top:9px;float:left}.search-bar .item-list .item{color:#333;background-color:#e6e7e8;margin-right:.5rem;display:inline-block;padding:6px;font-size:.8rem}.search-bar .item-list .item a{color:#fff}.search-bar .item-list .item a.remove:hover{cursor:pointer}.search-bar .search-selected{position:relative;padding-left:0;padding-right:0;background-color:#fff;color:#444}.search-bar .search-entry{width:18.5rem}.search-bar .search-input{width:100%;border:0;-webkit-box-shadow:none;box-shadow:none;margin:6px 0;background-color:#fff;color:#444;height:28px}.search-bar .search-input:focus{-webkit-box-shadow:none;box-shadow:none;background-color:#fff}.search-bar .match{font-weight:700}.search-bar i.cancel{color:#6a737b;position:absolute;top:.75rem;right:.65rem;font-size:18px}.search-bar i.cancel:hover{color:#8b0000;cursor:pointer}`] },] }, ]; /** @nocollapse */ NgxMagicSearchComponent.ctorParameters = () => [ { type: KeyValueDiffers, }, ]; NgxMagicSearchComponent.propDecorators = { "strings": [{ type: Input, args: ['strings',] },], "facets_param": [{ type: Input, args: ['facets_param',] },], "textSearchEvent": [{ type: Output },], "searchUpdatedEvent": [{ type: Output },], "compareEvent": [{ type: HostListener, args: ['document:click', ['$event'],] },], "trackEvent": [{ type: HostListener, args: ['click', ['$event'],] },], }; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class MyRenderer { /** * @param {?} platformId */ constructor(platformId) { this.platformId = platformId; } /** * @param {?} eleRef * @param {?} method * @return {?} */ invokeElementMethod(eleRef, method) { if (isPlatformBrowser(this.platformId)) { eleRef.nativeElement[method](); } } } MyRenderer.decorators = [ { type: Injectable }, ]; /** @nocollapse */ MyRenderer.ctorParameters = () => [ { type: Object, decorators: [{ type: Inject, args: [PLATFORM_ID,] },] }, ]; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class NgxMagicSearchDirective { /** * @param {?} el * @param {?} renderer */ constructor(el, renderer) { this.el = el; this.renderer = renderer; } /** * @return {?} */ ngOnChanges() { if (this.focusEvent) { this.renderer.invokeElementMethod(this.el.nativeElement, 'focus'); } } } NgxMagicSearchDirective.decorators = [ { type: Directive, args: [{ selector: '[ngxMagicSearch]' },] }, ]; /** @nocollapse */ NgxMagicSearchDirective.ctorParameters = () => [ { type: ElementRef, }, { type: MyRenderer, }, ]; NgxMagicSearchDirective.propDecorators = { "focusEvent": [{ type: Input },], }; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ class NgxMagicSearchModule { } NgxMagicSearchModule.decorators = [ { type: NgModule, args: [{ imports: [ CommonModule, FormsModule ], providers: [ MyRenderer, ], declarations: [ NgxMagicSearchComponent, NgxMagicSearchDirective ], exports: [ NgxMagicSearchComponent, NgxMagicSearchDirective ] },] }, ]; /** @nocollapse */ NgxMagicSearchModule.ctorParameters = () => []; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /** * Generated bundle index. Do not edit. */ export { NgxMagicSearchModule, NgxMagicSearchDirective as ɵc, NgxMagicSearchComponent as ɵb, MyRenderer as ɵa }; //# sourceMappingURL=ngx-magicsearch.js.map