novo-elements
Version:
Bullhorn's NOVO Element Repository for Angular 2
169 lines (150 loc) • 5.59 kB
text/typescript
// NG2
import { Component, Input, SimpleChanges, Output, EventEmitter, forwardRef, ElementRef, trigger, state, style, transition, animate, AfterContentInit, OnChanges, ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
// APP
import { Helpers } from '../../utils/Helpers';
// Value accessor for the component (supports ngModel)
const TILES_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NovoTilesElement),
multi: true
};
export class NovoTilesElement implements ControlValueAccessor, AfterContentInit, OnChanges {
name: string;
options: any;
required: boolean;
onChange: EventEmitter<any> = new EventEmitter();
onDisabledOptionClick: EventEmitter<any> = new EventEmitter();
_options: Array<any> = [];
public activeTile: any = null;
public state: String = 'inactive';
public focused: boolean = false;
model: any;
onModelChange: Function = () => {
};
onModelTouched: Function = () => {
};
constructor(private element: ElementRef, private ref: ChangeDetectorRef) {
}
public setFocus(focus: boolean): void {
this.focused = focus;
}
ngAfterContentInit() {
this.name = this.name || '';
this.setupOptions();
}
ngOnChanges(change: SimpleChanges) {
if (change['options'] && change['options'].currentValue && !change['options'].firstChange) {
this.name = this.name || '';
this._options = [];
this.setupOptions();
}
}
setupOptions() {
if (this.options && this.options.length && (this.options[0].value === undefined || this.options[0].value === null)) {
this._options = this.options.map((x) => {
let item = { value: x, label: x, checked: this.model === x };
if (item.checked) {
this.setTile(item);
}
return item;
});
} else {
this._options = this.options.map((x) => {
x.checked = this.model === x.value;
if (x.checked) {
this.setTile(x);
}
return x;
});
}
this.ref.markForCheck();
}
select(event, item) {
if (event) {
event.stopPropagation();
event.preventDefault();
}
if (item.checked) {
return;
}
if (!item.disabled) {
for (let option of this._options) {
option.checked = false;
}
item.checked = !item.checked;
this.onChange.emit(item.value);
this.onModelChange(item.value);
this.setTile(item);
this.model = item.value;
} else {
this.onDisabledOptionClick.emit(item);
}
this.ref.markForCheck();
}
setTile(item) {
if (item) {
this.activeTile = item.value;
this.moveTile();
}
}
moveTile() {
setTimeout(() => {
let ind = this.element.nativeElement.querySelector('.active-indicator');
let el = this.element.nativeElement.querySelector('.tile.active');
let w = el.clientWidth;
let left = el.offsetLeft;
// These style adjustments need to occur in this order.
setTimeout(() => {
ind.style.width = `${w + 4}px`;
setTimeout(() => {
ind.style.transform = `translateX(${left}px)`;
setTimeout(() => {
this.state = 'active';
this.ref.markForCheck();
});
});
});
});
}
writeValue(model: any): void {
this.model = model;
if (!Helpers.isBlank(model)) {
this.setupOptions();
}
}
registerOnChange(fn: Function): void {
this.onModelChange = fn;
}
registerOnTouched(fn: Function): void {
this.onModelTouched = fn;
}
}