src/app/shared/widgets/buy/search/search.component.ts
Properties |
|
autofocus |
autofocus:
|
Type : boolean
|
Optional |
Auto focus field. |
disableSearchOnEmptyField |
disableSearchOnEmptyField:
|
Type : boolean
|
Optional |
Enables/Disables searching with empty search term |
enableListsearch |
enableListsearch:
|
Type : boolean
|
Optional |
Enables/Disables the list search option |
enableListSearchOnly |
enableListSearchOnly:
|
Type : boolean
|
Optional |
Enables/Disables list search |
enableTemplating |
enableTemplating:
|
Type : boolean
|
Optional |
Enables/Disables using a template for the search and it's required for list search |
freetext-search-on-button |
freetext-search-on-button:
|
Type : boolean
|
Optional |
Enables freetext searching on button clicked @default(false) |
freetext-search-on-enter |
freetext-search-on-enter:
|
Type : boolean
|
Optional |
Enables freetext searching on enter clicked @default(true) |
header |
header:
|
Type : string
|
Optional |
Specifies the widget frame header type (default: primary) |
infoText |
infoText:
|
Type : string
|
Optional |
Sets info text to explain the widget freetext search functionality |
infoText-listsearch |
infoText-listsearch:
|
Type : string
|
Optional |
Sets info text to explain the widget list search functionality |
links |
links:
|
Type : any[]
|
Optional |
Sets link used for templating |
list-search-on-input |
list-search-on-input:
|
Type : boolean
|
Optional |
Enables list searching on input change @default(true) |
localstorage-listsearch |
localstorage-listsearch:
|
Type : string
|
Optional |
Sets local storage key name for the list search for saving the search term |
localstorage-search |
localstorage-search:
|
Type : string
|
Optional |
Sets local storage key name for saving the search term |
placeholderkey |
placeholderkey:
|
Type : string
|
Optional |
Sets the placeholder key for the search field @default(elasticsearch.search.paceholder) |
removeListSearchButton |
removeListSearchButton:
|
Type : boolean
|
Optional |
Sets label for the button removing the list search @default(false) |
scope |
scope:
|
Type : string
|
Optional |
Sets the scope of the widget to differenciate between local storage keys |
searchValue |
searchValue:
|
Type : boolean
|
Optional |
Enables setting the search term parameter to 'searchValue' instead of the 'q' default |
startListSearchLabel |
startListSearchLabel:
|
Type : string
|
Optional |
Sets label for the button starting the list search @default(searchlist.start) |
subheader |
subheader:
|
Type : string
|
Optional |
Sets subheader |
title |
title:
|
Type : string
|
Optional |
Sets title of the widget header in the freetext mode |
title-listsearch |
title-listsearch:
|
Type : string
|
Optional |
Sets title of the widget header in the list search mode |
width |
width:
|
Type : string
|
Optional |
Specifies the widget frame width |
wikiLink |
wikiLink:
|
Type : string
|
Optional |
Sets the link to the wiki documents to further explain the functionality |
withBorder |
withBorder:
|
Type : boolean
|
Optional |
Shows/Hides the widget frame border |
withHeader |
withHeader:
|
Type : boolean
|
Optional |
Specifies whether the widget should show the header or not @default(true) |
import {
combineLatest as observableCombineLatest,
Subject,
Observable,
ReplaySubject,
BehaviorSubject,
} from "rxjs";
import { distinctUntilChanged, filter, takeUntil } from "rxjs/operators";
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
OnInit,
ViewChild,
OnDestroy,
} from "@angular/core";
import { WidgetframeService } from "../../widgetframe/widgetframe.service";
import { WidgetConfig } from "../../widget.configuration";
import {
WidgetComponent,
WidgetConfiguration,
WidgetConfigure,
WidgetId,
WidgetInput,
WidgetOutput,
} from "../../widget.metadata";
import { FormBuilder, FormGroup } from "@angular/forms";
import { ListService } from "../../list/index";
import * as uriTemplates_ from "uri-templates";
import {
DeletionMode,
Scope,
} from "../../../components/local-storage/local-storage-constants";
import {
LocalStorageEntry,
LocalStorageService,
} from "../../../components/local-storage/local-storage.service";
import { getOrDefault } from "../../widget.configuration";
import { NgUnsubscribe } from "../../../ng-unsubscribe";
const uriTemplates = uriTemplates_;
export interface SearchWidgetConfiguration {
/** Enables/Disables the list search option */
enableListsearch?: boolean;
/** Enables/Disables list search */
enableListSearchOnly?: boolean;
/** Enables/Disables searching with empty search term */
disableSearchOnEmptyField?: boolean;
/** Enables/Disables using a template for the search and it's required for list search */
enableTemplating?: boolean;
/** Specifies whether the widget should show the header or not @default(true) */
withHeader?: boolean;
/** Sets the link to the wiki documents to further explain the functionality */
wikiLink?: string;
/** Sets link used for templating */
links?: any[];
/** Sets local storage key name for saving the search term */
"localstorage-search"?: string;
/** Sets the scope of the widget to differenciate between local storage keys */
scope?: string;
/** Sets local storage key name for the list search for saving the search term */
"localstorage-listsearch"?: string;
/** Sets the placeholder key for the search field @default(elasticsearch.search.paceholder) */
placeholderkey?: string;
/** Enables freetext searching on enter clicked @default(true) */
"freetext-search-on-enter"?: boolean;
/** Enables list searching on input change @default(true) */
"list-search-on-input"?: boolean;
/** Enables freetext searching on button clicked @default(false) */
"freetext-search-on-button"?: boolean;
/** Sets subheader */
subheader?: string;
/** Sets label for the button starting the list search @default(searchlist.start) */
startListSearchLabel?: string;
/** Sets label for the button removing the list search @default(false) */
removeListSearchButton?: boolean;
/** Enables setting the search term parameter to 'searchValue' instead of the 'q' default */
searchValue?: boolean;
/** Sets info text to explain the widget freetext search functionality */
infoText?: string;
/** Sets title of the widget header in the freetext mode */
title?: string;
/** Sets info text to explain the widget list search functionality */
"infoText-listsearch"?: string;
/** Sets title of the widget header in the list search mode */
"title-listsearch"?: string;
/** Shows/Hides the widget frame border */
withBorder?: boolean;
/** Specifies the widget frame header type (default: primary) */
header?: string;
/** Specifies the widget frame width */
width?: string;
/** Auto focus field. */
autofocus?: boolean;
}
@WidgetComponent("nm-search")
@Component({
selector: "nm-search",
templateUrl: "./search.component.html",
styleUrls: ["./search.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SearchWidgetComponent implements AfterViewInit, OnInit, OnDestroy {
public cols: any[];
private attributes: any;
public inputLink: string;
public wikiLink: string;
public infotext: string;
public title: string;
public subheader: string;
public inputLinklistSearch: string;
public enableListsearch: boolean;
public enableListSearchOnly: boolean;
public enableTemplating: boolean = true;
public withHeader: boolean = true;
public freetextSearchOnEnter: boolean = true;
public freetextSearchOnButton: boolean = false;
public placeholderkey: string;
public disableSearchOnEmptyField: boolean = false;
public autofocus: boolean = false;
private encodeLink: boolean = true;
public removeListSearchButton: boolean;
public startListSearchLabel: string;
private localStorageIsListSearchEntry: LocalStorageEntry;
private localStorageSearchEntry: LocalStorageEntry;
private localStorageListSearchEntry: LocalStorageEntry;
public hide: boolean = false;
private unsubscribe = NgUnsubscribe.create();
@WidgetConfiguration()
public configuration: WidgetConfig<SearchWidgetConfiguration>;
/**
* If templating is enabled emits the url that can be used to fetch the list-search data (if in list-search mode), else uses inputLink and fills it with the current search
*/
@WidgetOutput("uri")
private uri: Subject<any> = new ReplaySubject<any>(1);
/**
* Emits the user input if templating is disabled and search mode is list
*/
@WidgetOutput("listSearchOutput")
private listSearchOutput: Subject<any> = new ReplaySubject<any>(1);
/**
* Emits the current search mode ('freeTextSearch' or 'listSearch')
*/
@WidgetOutput("modeischanged")
private modeIsChanged: Subject<any> = new ReplaySubject<any>(1);
/**
* Deprecated
*/
@WidgetOutput("profile")
private profile: Subject<any> = new ReplaySubject<any>(1);
/**
* Resets the search
*/
@WidgetInput("reset")
private resetChannel: Subject<any> = new Subject<any>();
/**
* Hides the search widget
*/
@WidgetInput("hide")
private hideChannel: Subject<any> = new Subject<any>();
/**
* Sets the value of the search-field and performs a search
*/
@WidgetInput("set")
private inputChannel: Subject<any> = new BehaviorSubject<any>(null);
/**
* Clears search term
*/
@WidgetInput("cleartextsearch")
private clearChannel: Subject<any> = new Subject<any>();
/**
* Emits every time a search is performed (meant to force a reset of category-search, which are often used in conjunction with this)
*/
@WidgetOutput("clearcategorysearch")
private clearCategorySearch: Subject<any> = new Subject<any>();
/**
* Triggers when return is pressed on the search field (if the mode is not list-search)
*/
@WidgetOutput("returnPressed")
private returnPressed: Subject<any> = new Subject<any>();
/**
* Emits the search term everytime it changes
*/
@WidgetOutput("searchTerm")
private searchTerm: Subject<any> = new Subject<any>();
/**
* Triggers saving the search input in the local storage
*/
@WidgetInput("saveSearchTerm")
private saveSearchTerm: Subject<any> = new Subject<any>();
private storageValue: Subject<any> = new ReplaySubject<any>(1);
/**
* Emits data on list search input, if enableTemplating = true
*/
@WidgetOutput("listSearchOnChangeOutput")
private listSearchOnChangeOutput: Subject<any> = new ReplaySubject<any>(1);
@WidgetId()
public _id: string;
@ViewChild("inputComponent") inputComponent;
private sub;
public searchform: FormGroup;
public listsearch: boolean = false;
constructor(
private _widgetframeService: WidgetframeService,
private formBuilder: FormBuilder,
private _listService: ListService,
private localStorageService: LocalStorageService,
private _changeDetectorRef: ChangeDetectorRef
) {
this.searchform = this.formBuilder.group({
searchInput: "",
});
}
setSearchTerm(value) {
this.searchform.value.searchInput = value;
if (this.localStorageListSearchEntry) {
this.localStorageListSearchEntry.value = value;
}
}
keyDownFunction(event) {
if (this.freetextSearchOnEnter && !this.listsearch) {
this.doFreetextSearch(this.searchform.value.searchInput);
this.returnPressed.next(new Date());
this._changeDetectorRef.markForCheck();
}
}
onChange(event) {
this.searchTerm.next(this.searchform.value.searchInput);
if (!this.freetextSearchOnEnter && !this.freetextSearchOnButton) {
this.doFreetextSearch(this.searchform.value.searchInput);
this._changeDetectorRef.markForCheck();
}
}
doListSearch(value) {
this.clearCategorySearch.next(Date.now);
if (this.localStorageListSearchEntry) {
this.localStorageListSearchEntry.value = value;
}
this._changeDetectorRef.markForCheck();
if (this.enableTemplating && this.encodeLink) {
this._widgetframeService
.postData(this.inputLinklistSearch, value)
.subscribe((data) => {
this.uri.next(data._links.results.href);
});
} else {
this.listSearchOutput.next(value);
}
}
doFreetextSearch(value) {
this.clearCategorySearch.next(Date.now);
if (this.localStorageSearchEntry) {
this.localStorageSearchEntry.value = value;
}
if (this.enableTemplating && this.encodeLink) {
let uriParams;
if (this.configuration.configuration["searchValue"]) {
uriParams = { searchValue: value };
} else {
uriParams = { q: value };
}
if (!(this.disableSearchOnEmptyField && uriParams["q"].length === 0)) {
let link = uriTemplates(this.inputLink).fill(uriParams);
this.uri.next(link);
}
} else {
if (!(this.disableSearchOnEmptyField && value.length === 0)) {
this.uri.next(value);
}
}
this._changeDetectorRef.markForCheck();
}
toggleMode($event) {
if ($event.checked) {
this.switchToListSearch();
} else {
this.switchToFreetextSearch();
}
}
private switchToFreetextSearch() {
this.modeIsChanged.next("freeTextSearch");
this.listsearch = false;
this.localStorageIsListSearchEntry.value = "false";
this.infotext = this.configuration.configuration["infoText"];
this.title = this.configuration.configuration["title"];
this.resetFromLocalStorage(this.localStorageSearchEntry);
}
private switchToListSearch() {
this.modeIsChanged.next("listSearch");
this.listsearch = true;
this.localStorageIsListSearchEntry.value = "true";
this.infotext = this.configuration.configuration["infoText-listsearch"];
this.title = this.configuration.configuration["title-listsearch"];
this.resetFromLocalStorage(this.localStorageListSearchEntry);
}
resetFromLocalStorage(entry: LocalStorageEntry) {
if (entry) {
let value = entry.value;
this.storageValue.next(value);
this.updateTextField(value);
}
}
private updateTextField(value: string) {
this.searchform.setValue({
searchInput: value || "",
});
window.setTimeout(() => {
this.searchform.patchValue({
searchInput: value || "",
});
this._changeDetectorRef.markForCheck();
}, 1);
}
doSearch(value) {
this.updateTextField(value);
if (this.listsearch || this.enableListSearchOnly) {
this.doListSearch(value);
} else {
this.doFreetextSearch(value);
}
}
onListValueChange(value) {
this.listSearchOnChangeOutput.next(value);
if (this.localStorageListSearchEntry && this.removeListSearchButton) {
this.localStorageListSearchEntry.value = value;
}
}
@WidgetConfigure()
protected configureWidget(configuration: WidgetConfig) {
this.enableListsearch = this.configuration.configuration[
"enableListsearch"
];
this.enableListSearchOnly = this.configuration.configuration[
"enableListSearchOnly"
];
this.disableSearchOnEmptyField = this.configuration.configuration[
"disableSearchOnEmptyField"
];
if (this.configuration.configuration["enableTemplating"] != undefined) {
this.enableTemplating = this.configuration.configuration[
"enableTemplating"
];
}
if (this.configuration.configuration["withHeader"] != undefined) {
this.withHeader = this.configuration.configuration["withHeader"];
}
this.wikiLink = this.configuration.configuration["wikiLink"];
if (this.configuration.configuration["links"]) {
this.inputLink = this.configuration.configuration["links"]["search"];
this.inputLinklistSearch = this.configuration.configuration["links"][
"listSearch"
];
}
if (this.configuration.configuration["localstorage-search"]) {
this.localStorageSearchEntry = this.localStorageService.getLocalStorageEntry(
this.configuration.configuration["scope"] +
this.configuration.configuration["localstorage-search"],
Scope.GLOBAL,
DeletionMode.RESET
);
}
if (this.configuration.configuration["localstorage-listsearch"]) {
this.localStorageListSearchEntry = this.localStorageService.getLocalStorageEntry(
this.configuration.configuration["scope"] +
this.configuration.configuration["localstorage-listsearch"],
Scope.GLOBAL,
DeletionMode.RESET
);
}
this.localStorageIsListSearchEntry = this.localStorageService.getLocalStorageEntry(
this.configuration.configuration["scope"] + "nm-product-listsearch",
Scope.GLOBAL,
DeletionMode.RESET
);
this.placeholderkey = this.configuration.configuration["placeholderkey"]
? this.configuration.configuration["placeholderkey"]
: "elasticsearch.search.paceholder";
this.freetextSearchOnEnter =
this.configuration.configuration["freetext-search-on-enter"] !== undefined
? this.configuration.configuration["freetext-search-on-enter"]
: true;
this.encodeLink =
this.configuration.configuration["list-search-on-input"] !== undefined
? this.configuration.configuration["list-search-on-input"]
: true;
this.freetextSearchOnButton =
this.configuration.configuration["freetext-search-on-button"] !==
undefined
? this.configuration.configuration["freetext-search-on-button"]
: false;
if (this.freetextSearchOnButton) {
this.freetextSearchOnEnter = false;
}
this.withHeader =
this.configuration.configuration["withHeader"] !== undefined
? this.configuration.configuration["withHeader"]
: true;
this.subheader =
this.configuration.configuration["subheader"] !== undefined
? this.configuration.configuration["subheader"]
: "";
this.startListSearchLabel = getOrDefault(
this.configuration.configuration["startListSearchLabel"],
"searchlist.start"
);
this.removeListSearchButton = getOrDefault(
this.configuration.configuration["removeListSearchButton"],
false
);
this.autofocus = getOrDefault(
this.configuration.configuration["autofocus"],
false
);
if (
this.localStorageIsListSearchEntry.exists() &&
(this.enableListsearch || this.enableListSearchOnly)
) {
this.listsearch =
this.localStorageIsListSearchEntry.value === "true" ? true : false;
}
if (this.listsearch || this.enableListSearchOnly) {
this.switchToListSearch();
} else {
this.switchToFreetextSearch();
}
this.resetChannel
.asObservable()
.pipe(takeUntil(this.unsubscribe))
.subscribe((reset) => {
this.searchform.value.searchInput = null;
if (this.localStorageSearchEntry) {
this.localStorageSearchEntry.clear();
}
if (this.localStorageListSearchEntry) {
this.localStorageListSearchEntry.clear();
}
this.doSearch("");
this._changeDetectorRef.markForCheck();
});
this.clearChannel
.asObservable()
.pipe(takeUntil(this.unsubscribe))
.subscribe((reset) => {
this.localStorageSearchEntry.clear();
if (this.localStorageListSearchEntry) {
this.localStorageListSearchEntry.clear();
}
this.updateTextField("");
this._changeDetectorRef.markForCheck();
});
this.saveSearchTerm
.asObservable()
.pipe(takeUntil(this.unsubscribe))
.subscribe((save) => {
this.localStorageSearchEntry.value = this.searchform.value.searchInput;
});
this.hideChannel
.asObservable()
.pipe(takeUntil(this.unsubscribe))
.subscribe((hide) => {
this.hide = hide;
});
}
public ngOnInit() {
observableCombineLatest(
this.storageValue,
this.inputChannel,
(storage, input) => {
if (input) {
return input;
}
return storage;
}
)
.pipe(
filter((value) => value),
distinctUntilChanged(),
takeUntil(this.unsubscribe)
)
.subscribe((value) => this.doSearch(value));
}
ngAfterViewInit() {
if (!this.listsearch) {
this.searchTerm.next(this.searchform.value.searchInput);
}
if (this.inputComponent && this.inputComponent.first) {
setTimeout(() => {
this.inputComponent.first.nativeElement.focus();
this._changeDetectorRef.markForCheck();
}, 1);
}
}
ngAfterViewChecked() {
this._changeDetectorRef.markForCheck();
}
ngOnDestroy() {
this.unsubscribe.destroy();
}
}