UNPKG

novo-elements

Version:

Bullhorn's NOVO Element Repository for Angular 2

187 lines (172 loc) 8 kB
import { Component, ElementRef, ViewChild, OnInit, OnDestroy, Renderer2 } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { Subscription } from 'rxjs/Subscription'; import { BasePickerResults } from '../base-picker-results/BasePickerResults'; import { Helpers } from '../../../../utils/Helpers'; import { NovoListElement } from '../../../list/List'; import { NovoLabelService } from '../../../../services/novo-label-service'; @Component({ selector: 'grouped-multi-picker-results', template: ` <div class="grouped-multi-picker-groups"> <novo-list direction="vertical"> <novo-list-item *ngIf="config.displayAll" (click)="selectCategory({ value: 'all', label: 'all' })" [class.active]="selectedCategory === 'all'" [class.disabled]="isLoading"> <item-content> <span>{{ labels.all }}</span> </item-content> <item-end> <i class="bhi-next"></i> </item-end> </novo-list-item> <novo-list-item *ngFor="let category of categories" (click)="selectCategory(category)" [class.active]="selectedCategory === category.value" [class.disabled]="isLoading"> <item-content> <span>{{ category.label }}</span> </item-content> <item-end> <i class="bhi-next"></i> </item-end> </novo-list-item> </novo-list> </div> <div class="grouped-multi-picker-matches"> <div class="grouped-multi-picker-input-container" [hidden]="!selectedCategory"> <input autofocus #input [(ngModel)]="searchTerm" [disabled]="isLoading"/> <i class="bhi-search" *ngIf="!searchTerm" [class.disabled]="isLoading"></i> <i class="bhi-times" *ngIf="searchTerm" (click)="clearSearchTerm($event)" [class.disabled]="isLoading"></i> </div> <novo-list direction="vertical" #list> <novo-list-item *ngFor="let match of matches" (click)="selectMatch($event)" [class.active]="match === activeMatch" (mouseenter)="selectActive(match)" [class.disabled]="preselected(match)" [class.disabled]="isLoading"> <item-content> <span>{{ match.label }}</span> </item-content> </novo-list-item> </novo-list> <div class="grouped-multi-picker-no-results" *ngIf="matches.length === 0 && !isLoading"> {{ labels.groupedMultiPickerEmpty }} </div> <div class="grouped-multi-picker-loading" *ngIf="isLoading"> <novo-loading theme="line"></novo-loading> </div> </div> ` }) export class GroupedMultiPickerResults extends BasePickerResults implements OnInit, OnDestroy { @ViewChild('input') private inputElement: ElementRef; @ViewChild('list') private listElement: NovoListElement; public selectedCategory: string; public searchTerm: string; private keyboardSubscription: Subscription; private internalMap: Map<string, { value: string, label: string, items: { value: string, label: string }[] }> = new Map<string, { value: string, label: string, items: { value: string, label: string }[] }>(); set term(value) { // Display all only will work for static categories if (this.config.displayAll && this.config.getItemsForCategoryAsync) { throw new Error('[NovoChips] - you can only have `displayAll` with a static `categoryMap`. Not available with `getItemsForCategoryAsync`'); } if (this.config.displayAll) { // Focus setTimeout(() => { this.inputElement.nativeElement.focus(); }); this.setAllCategory(); } } get categories() { if (this.config.categories || this.config.categoryMap) { return this.config.categories || Array.from(this.config.categoryMap.values()); } return []; } constructor(element: ElementRef, private renderer: Renderer2, public labels: NovoLabelService) { super(element); } public ngOnInit() { // Subscribe to keyboard events and debounce this.keyboardSubscription = Observable.fromEvent(this.inputElement.nativeElement, 'keyup') .debounceTime(350) .distinctUntilChanged() .subscribe((event: KeyboardEvent) => { this.searchTerm = event.target['value']; this.matches = this.filterData(); }); } public ngOnDestroy() { // Cleanup this.keyboardSubscription.unsubscribe(); } public setAllCategory() { // If we have display all, set the all categories up if (this.config.displayAll) { this.selectedCategory = 'all'; let allItems = []; Array.from(this.config.categoryMap.values()).forEach((v: { value: string, label: string, items: any[] }) => allItems.push(...v.items)); this.matches = allItems; this.config.categoryMap.set('all', { value: 'all', label: 'All', items: allItems }); } } public selectCategory(category: { value: string, label: string }): void { // Scroll to top this.renderer.setProperty(this.listElement.element.nativeElement, 'scrollTop', 0); // Set focus this.inputElement.nativeElement.focus(); // Find new items let key: string = category.value; this.selectedCategory = key; // Clear this.matches = []; // Get new matches if (this.config.categoryMap) { this.matches = this.filter(this.config.categoryMap.get(key).items); } else { if (!this.config.getItemsForCategoryAsync) { throw new Error('The "config" for the Chips must include a function "getItemsForCategoryAsync(categoryKey: string)" to retrieve the items by category. Or if you have static data provide a "categoryMap"'); } if (!this.internalMap.get(key)) { this.isLoading = true; this.config.getItemsForCategoryAsync(key).then((items: { value: string, label: string }[]) => { this.internalMap.set(key, { value: category.value, label: category.label, items: items }); this.matches = this.filter(items); this.isLoading = false; }); } else { this.matches = this.filter(this.internalMap.get(key).items); } } } public clearSearchTerm(event: MouseEvent) { Helpers.swallowEvent(event); this.searchTerm = ''; this.selectCategory({ value: this.selectedCategory, label: '' }); } filterData(): { value: string, label: string }[] { if (this.selectedCategory) { if (this.config.categoryMap) { return this.filter(this.config.categoryMap.get(this.selectedCategory).items); } else { return this.filter(this.internalMap.get(this.selectedCategory).items); } } return []; } private filter(array: { value: string, label: string }[]): { value: string, label: string }[] { if (this.searchTerm && this.searchTerm.length !== 0 && this.selectedCategory) { return array.filter((match) => { return ~String(match.label).toLowerCase().indexOf(this.searchTerm.toLowerCase()); }); } return array; } }