Created
August 16, 2019 15:02
-
-
Save nettakogo87/6e0a62722fdd7e2be278a754af665130 to your computer and use it in GitHub Desktop.
Angular control
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<mat-form-field class="evv-full-width"> | |
<mat-placeholder>{{placeholder}}</mat-placeholder> | |
<mat-chip-list | |
#chipList | |
[disabled]="itemsCtrl.disabled" | |
[required]="required"> | |
<mat-chip | |
*ngFor="let selectedItem of selectedItems; let index = index" | |
color="primary" | |
selected="false" | |
[removable]="itemsCtrl.enabled" | |
(removed)="removeByIndex(index)"> | |
<ng-container | |
*ngTemplateOutlet="itemRowTemplateRef; context: {$implicit: selectedItem}"> | |
</ng-container> | |
<mat-icon matChipRemove>cancel</mat-icon> | |
</mat-chip> | |
<input | |
matInput | |
#itemsInput | |
[formControl]="itemsCtrl" | |
[matAutocomplete]="autoItem" | |
[matChipInputFor]="chipList" | |
[attr.aria-label]="placeholder"> | |
</mat-chip-list> | |
<mat-autocomplete | |
#autoItem="matAutocomplete" | |
(optionSelected)="select($event)"> | |
<mat-option | |
*ngFor="let filteredItem of filteredItems | async" | |
[value]="filteredItem"> | |
<ng-container | |
*ngTemplateOutlet="itemRowTemplateRef; context: {$implicit: filteredItem}"> | |
</ng-container> | |
</mat-option> | |
</mat-autocomplete> | |
<mat-error *ngIf="required"> | |
<ng-container *ngTemplateOutlet="itemErrorsTemplateRef; context: {$implicit: multi}"> | |
</ng-container> | |
</mat-error> | |
</mat-form-field> | |
<!-- Templates --> | |
<ng-content> | |
</ng-content> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ANGULAR | |
import { | |
ChangeDetectionStrategy, | |
Component, | |
ElementRef, | |
EventEmitter, | |
Input, | |
OnDestroy, | |
OnInit, | |
Optional, | |
Output, | |
Self, | |
ViewChild, | |
} from '@angular/core'; | |
import { ControlValueAccessor, FormControl, NgControl } from '@angular/forms'; | |
import { MatAutocompleteSelectedEvent } from '@angular/material'; | |
// RXJS | |
import { Observable, Subject } from 'rxjs'; | |
import { debounceTime, takeUntil } from 'rxjs/operators'; | |
@Component({ | |
selector: 'evv-chips-autocomplete', | |
templateUrl: './chips-autocomplete.component.html', | |
styleUrls: ['./chips-autocomplete.component.scss'], | |
changeDetection: ChangeDetectionStrategy.OnPush, | |
}) | |
export class ChipsAutocompleteComponent<T> implements OnInit, OnDestroy, ControlValueAccessor { | |
@Input() | |
public placeholder = 'Select'; | |
@Input() | |
public filteredItems: Observable<T[]>; | |
@Input() | |
public multi = false; | |
@Input() | |
public required = false; | |
@Input() | |
public itemRowTemplateRef: any; | |
@Input() | |
public itemErrorsTemplateRef: any; | |
@Output() | |
public searchChanged = new EventEmitter<string>(); | |
@ViewChild('chipList') | |
public chipList; | |
@ViewChild('itemsInput') | |
public itemsInput: ElementRef; | |
public itemsCtrl = new FormControl(''); | |
protected _onChange = (value: any) => {}; | |
protected _onTouched = () => {}; | |
private _selectedItems: T[] = []; | |
private _destroyed$ = new Subject<void>(); | |
constructor( | |
@Optional() @Self() private _ngControl: NgControl, | |
) { | |
if (this._ngControl) { | |
this._ngControl.valueAccessor = this; | |
} | |
} | |
public get selectedItems(): T[] { | |
return this._selectedItems; | |
} | |
public ngOnInit(): void { | |
this._subItemsControlChanged(); | |
this._subStatusChanged(); | |
} | |
public ngOnDestroy(): void { | |
this._destroyed$.next(); | |
this._destroyed$.complete(); | |
} | |
public registerOnChange(fn: any): void { | |
this._onChange = fn; | |
} | |
public registerOnTouched(fn: any): void { | |
this._onTouched = fn; | |
} | |
public setDisabledState(isDisabled: boolean): void { | |
if (isDisabled) { | |
this.itemsCtrl.disable(); | |
} else { | |
this.itemsCtrl.enable(); | |
} | |
} | |
public writeValue(items: T[]): void { | |
this._selectedItems = items.slice(); | |
} | |
public select(event: MatAutocompleteSelectedEvent): void { | |
if (event.option.value) { | |
if (!this.multi) { | |
this._selectedItems.length = 0; | |
} | |
this._selectedItems.push(event.option.value); | |
this._onChange(this._selectedItems.slice()); | |
} | |
this.itemsInput.nativeElement.value = ''; | |
this.itemsCtrl.setValue(''); | |
} | |
public removeByIndex(index: number): void { | |
this._selectedItems.splice(index, 1); | |
this.itemsCtrl.setValue(''); | |
this._onChange(this._selectedItems.slice()); | |
} | |
private _subItemsControlChanged(): void { | |
this.itemsCtrl.valueChanges | |
.pipe( | |
debounceTime(500), | |
takeUntil(this._destroyed$), | |
) | |
.subscribe((searchQuery: string) => { | |
this.searchChanged.emit(searchQuery); | |
}); | |
} | |
private _subStatusChanged(): void { | |
this._ngControl.statusChanges | |
.pipe( | |
takeUntil(this._destroyed$), | |
) | |
.subscribe((ctrlStatus) => { | |
this.chipList.errorState = ctrlStatus === 'INVALID'; | |
}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<evv-chips-autocomplete | |
#selectRecipientsInput | |
class="pad-bottom-sm" | |
placeholder="Select Recipients" | |
[formControl]="recipientsCtrl" | |
[filteredItems]="filteredRecipients" | |
[multi]="false" | |
[required]="true" | |
[itemRowTemplateRef]="itemRow" | |
[itemErrorsTemplateRef]="itemErrorMessages" | |
(searchChanged)="searchChanged($event)"> | |
<ng-template #itemRow let-recipient> | |
<evv-select-recipient-template [recipient]="recipient"> | |
</evv-select-recipient-template> | |
</ng-template> | |
<ng-template #itemErrorMessages let-multi> | |
<ng-container *ngIf="multi">Recipients are required!</ng-container> | |
<ng-container *ngIf="!multi">Recipient is required!</ng-container> | |
</ng-template> | |
</evv-chips-autocomplete> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment