File

projects/rebirth-ng/src/lib/select/select.component.ts

Implements

OnInit ControlValueAccessor

Metadata

changeDetection ChangeDetectionStrategy.OnPush
exportAs select
providers { : , : (() => ), : true }
selector re-select
styleUrls select.component.scss
templateUrl ./select.component.html

Index

Properties
Methods
Inputs
Outputs
HostListeners

Constructor

constructor(changeDetectorRef: ChangeDetectorRef, elementRef: ElementRef, rebirthNgConfig: RebirthNGConfig)
Parameters :
Name Type Optional
changeDetectorRef ChangeDetectorRef no
elementRef ElementRef no
rebirthNgConfig RebirthNGConfig no

Inputs

direction

Type: "down" | "up"

Default value: 'down'

disabled

Type: boolean

formatter

Type: function

groupOptions

Type: []

iconDown

Type: string

itemTemplate

Type: TemplateRef<any>

options

Type: []

placeholder

Type: string

Outputs

onSelect $event type: EventEmitter

HostListeners

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: )

Methods

Private changeValue
changeValue(value: any)
Parameters :
Name Type Optional
value any no
Returns : void
isGroupItem
isGroupItem(item: any)
Parameters :
Name Type Optional
item any no
Returns : boolean
ngOnInit
ngOnInit()
Returns : void
onActiveIndexChange
onActiveIndexChange(index: )
Parameters :
Name Optional
index no
Returns : number
onPopupToggle
onPopupToggle(isPopup?: boolean)
Parameters :
Name Type Optional
isPopup boolean yes
Returns : void
onSelectedChange
onSelectedChange(value: any)
Parameters :
Name Type Optional
value any no
Returns : void
registerOnChange
registerOnChange(fn: any)
Parameters :
Name Type Optional
fn any no
Returns : void
registerOnTouched
registerOnTouched(fn: any)
Parameters :
Name Type Optional
fn any no
Returns : void
setDisabledState
setDisabledState(isDisabled: boolean)
Parameters :
Name Type Optional
isDisabled boolean no
Returns : void
Private updateActiveIndex
updateActiveIndex()
Returns : void
writeValue
writeValue(value: any)
Parameters :
Name Type Optional
value any no
Returns : void

Properties

Private _groupOptions
_groupOptions: GroupOption[]
Type : GroupOption[]
Private _options
_options: any[]
Type : any[]
activeIndex
activeIndex: number
Type : number
Default value : 0
arrowState
arrowState: string
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: any
Type : any
selectedText
selectedText: string
Type : string

Accessors

groupOptions
setgroupOptions(group: [])
Parameters :
Name Type Optional
group [] no
Returns : void
options
getoptions()
setoptions(options: [])
Parameters :
Name Type Optional
options [] no
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>
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""