projects/rebirth-ng/src/lib/select/select.component.ts
changeDetection | ChangeDetectionStrategy.OnPush |
exportAs | select |
providers |
{
: , : (() => ), : true
}
|
selector | re-select |
styleUrls | select.component.scss |
templateUrl | ./select.component.html |
Properties |
|
Methods |
Inputs |
Outputs |
HostListeners |
constructor(changeDetectorRef: ChangeDetectorRef, elementRef: ElementRef, rebirthNgConfig: RebirthNGConfig)
|
||||||||||||
Parameters :
|
direction
|
Type:
Default value: |
disabled
|
Type: |
formatter
|
Type: |
groupOptions
|
Type: |
iconDown
|
Type: |
itemTemplate
|
Type: |
options
|
Type: |
placeholder
|
Type: |
onSelect
|
$event type: EventEmitter
|
document:click |
Arguments : '$event'
|
document:click($event: Event)
|
keydown.ArrowDown |
Arguments : '$event'
|
keydown.ArrowDown($event: )
|
keydown.ArrowUp |
Arguments : '$event'
|
keydown.ArrowUp($event: )
|
keydown.Enter |
Arguments : '$event'
|
keydown.Enter($event: )
|
keydown.esc |
Arguments : '$event'
|
keydown.esc($event: )
|
Private changeValue | ||||||
changeValue(value: any)
|
||||||
Parameters :
Returns :
void
|
isGroupItem | ||||||
isGroupItem(item: any)
|
||||||
Parameters :
Returns :
boolean
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
onActiveIndexChange | ||||
onActiveIndexChange(index: )
|
||||
Parameters :
Returns :
number
|
onPopupToggle | ||||||
onPopupToggle(isPopup?: boolean)
|
||||||
Parameters :
Returns :
void
|
onSelectedChange | ||||||
onSelectedChange(value: any)
|
||||||
Parameters :
Returns :
void
|
registerOnChange | ||||||
registerOnChange(fn: any)
|
||||||
Parameters :
Returns :
void
|
registerOnTouched | ||||||
registerOnTouched(fn: any)
|
||||||
Parameters :
Returns :
void
|
setDisabledState | ||||||
setDisabledState(isDisabled: boolean)
|
||||||
Parameters :
Returns :
void
|
Private updateActiveIndex |
updateActiveIndex()
|
Returns :
void
|
writeValue | ||||||
writeValue(value: any)
|
||||||
Parameters :
Returns :
void
|
Private _groupOptions |
_groupOptions:
|
Type : GroupOption[]
|
Private _options |
_options:
|
Type : any[]
|
activeIndex |
activeIndex:
|
Type : number
|
Default value : 0
|
arrowState |
arrowState:
|
Type : string
|
Default value : 'down'
|
isPopup |
isPopup:
|
Default value : false
|
Private onChange |
onChange:
|
Default value : (_: any) => null
|
Private onTouched |
onTouched:
|
Default value : () => null
|
selectedItem |
selectedItem:
|
Type : any
|
selectedText |
selectedText:
|
Type : string
|
groupOptions | ||||||
setgroupOptions(group: [])
|
||||||
Parameters :
Returns :
void
|
options | ||||||
getoptions()
|
||||||
setoptions(options: [])
|
||||||
Parameters :
Returns :
void
|
import {
Component,
Input,
Output,
forwardRef,
EventEmitter,
HostListener,
ElementRef,
TemplateRef,
OnInit,
SimpleChanges,
SimpleChange,
ChangeDetectorRef,
ChangeDetectionStrategy
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { RebirthNGConfig } from '../rebirth-ng.config';
import {
trigger,
state,
transition,
animate,
style
} from '@angular/animations';
import { GroupOption } from './select.model';
@Component({
selector: 're-select',
templateUrl: './select.component.html',
styleUrls: ['./select.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs: 'select',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SelectComponent),
multi: true
}
],
animations: [
trigger('arrowState', [
state(
'down',
style({
transform: 'rotate(0deg)'
})
),
state(
'up',
style({
transform: 'rotate(180deg)'
})
),
transition('down => up', animate('200ms ease-in')),
transition('up => down', animate('200ms ease-out'))
])
]
})
export class SelectComponent implements OnInit, ControlValueAccessor {
@Input() disabled: boolean;
@Input() placeholder: string;
@Input() iconDown: string;
@Input() direction: 'down' | 'up' = 'down';
@Input() itemTemplate: TemplateRef<any>;
@Input() formatter: (obj: any) => string;
@Output() onSelect = new EventEmitter<any>();
arrowState = 'down';
activeIndex = 0;
selectedItem: any;
selectedText: string;
isPopup = false;
private _groupOptions: GroupOption[];
private _options: any[];
private onChange = (_: any) => null;
private onTouched = () => null;
constructor(
private changeDetectorRef: ChangeDetectorRef,
private elementRef: ElementRef,
rebirthNgConfig: RebirthNGConfig
) {
this.iconDown = rebirthNgConfig.select.iconDown;
this.formatter = rebirthNgConfig.select.formatter;
}
@Input()
set groupOptions(group: GroupOption[]) {
if (group && this._groupOptions !== group) {
this._options = group.reduce((opts, item) => {
if (item.options && item.options.length) {
opts.push({ group: item }, ...item.options);
}
if (this.selectedItem) {
setTimeout(() => this.changeValue(null));
}
return opts;
}, []);
}
this._groupOptions = group;
}
@Input()
set options(options: any[]) {
if (options !== this._options) {
this._options = options;
if (this.selectedItem) {
setTimeout(() => this.changeValue(null));
}
}
}
get options(): any[] {
return this._options;
}
ngOnInit(): void {
this.arrowState = this.direction;
}
writeValue(value: any): void {
this.changeValue(value);
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
onPopupToggle(isPopup?: boolean) {
if (!this.disabled) {
if (isPopup === undefined) {
isPopup = !this.isPopup;
}
this.isPopup = isPopup;
let status = { false: 'down', true: 'up' };
if (this.direction === 'up') {
status = { false: 'up', true: 'down' };
}
this.arrowState = status[isPopup.toString()];
this.updateActiveIndex();
}
}
onSelectedChange(value: any) {
this.onTouched();
this.changeValue(value);
this.onPopupToggle(false);
this.onSelect.emit(value);
}
onActiveIndexChange(index) {
this.activeIndex = (index + this._options.length) % this._options.length;
return this.activeIndex;
}
@HostListener('keydown.esc', ['$event'])
onEscKeyup($event) {
this.onPopupToggle(false);
}
@HostListener('keydown.Enter', ['$event'])
onEnterKeyDown($event) {
if (this.isPopup) {
$event.preventDefault();
$event.stopPropagation();
this.onSelectedChange(this._options[this.activeIndex]);
}
}
@HostListener('keydown.ArrowUp', ['$event'])
onArrowUpKeyDown($event) {
if (this.isPopup) {
$event.preventDefault();
$event.stopPropagation();
const index = this.onActiveIndexChange(this.activeIndex - 1);
if (this.isGroupItem(this._options[index])) {
this.onActiveIndexChange(this.activeIndex - 1);
}
}
}
@HostListener('keydown.ArrowDown', ['$event'])
onArrowDownKeyDown($event) {
if (this.isPopup) {
$event.preventDefault();
$event.stopPropagation();
const index = this.onActiveIndexChange(this.activeIndex + 1);
if (this.isGroupItem(this._options[index])) {
this.onActiveIndexChange(this.activeIndex + 1);
}
}
}
@HostListener('document:click', ['$event'])
onDocumentClick($event: Event) {
const hostElement = this.elementRef.nativeElement;
if (!hostElement.contains($event.target)) {
this.onPopupToggle(false);
}
}
isGroupItem(item: any): boolean {
return item.group;
}
private changeValue(value: any) {
this.selectedItem = value;
this.selectedText = value ? this.formatter(value) : '';
this.updateActiveIndex();
this.onChange(value);
this.changeDetectorRef.markForCheck();
}
private updateActiveIndex() {
if (this._options && this.selectedItem) {
this.activeIndex = this._options.indexOf(this.selectedItem);
}
}
}
<ng-template #defaultItemTemplate let-formatter="formatter" let-item="item">
{{formatter(item)}}
</ng-template>
<div class="drop{{direction}} select-container">
<div class="input-group select-panel" [ngClass]="{disabled: disabled}" (click)="onPopupToggle()">
<input type="text" class="form-control select-control" [disabled]="disabled" readonly="readonly" unselectable="on"
[placeholder]="placeholder" [(ngModel)]="selectedText" (ngModelChange)="onSelectedChange($event)"/>
<div class="input-group-addon" [ngClass]="{disabled: disabled}">
<i class="select-down-icon {{iconDown}}" [@arrowState]="arrowState"></i>
</div>
</div>
<div class="dropdown-menu" [style.display]="isPopup ? 'block' : 'none'">
<ul class="list-unstyled popup-list">
<ng-container *ngFor="let item of options; let $index = index;">
<li *ngIf="item.group" class="dropdown-header">{{item.group?.group}}</li>
<li *ngIf="!item.group" class="dropdown-item"
[ngClass]="{'item-hoverd bg-primary': $index == activeIndex, selected: selectedItem == item}"
(click)="onSelectedChange(item)"
(mouseenter)="onActiveIndexChange($index)">
<ng-template [ngTemplateOutlet]="itemTemplate || defaultItemTemplate"
[ngTemplateOutletContext]="{ formatter: formatter, selectedItem:selectedItem, selectedText:selectedText, options:options, item:item, $index:$index}"></ng-template>
</li>
</ng-container>
</ul>
</div>
</div>