ng2-encrm-components
Version:
253 lines (213 loc) • 6.76 kB
text/typescript
import {
forwardRef,
Component,
HostBinding,
Input,
SimpleChange,
ViewChild,
ElementRef,
EventEmitter,
Output
} from '@angular/core';
import {
NG_VALUE_ACCESSOR
} from '@angular/forms';
import { BooleanFieldValue } from './../annotations/field-value';
import { Observable } from 'rxjs/Observable';
const noop = () => {
};
export const EN_INPUT_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => EnInputComponent),
multi: true
};
// Invalid input type. Using one of these will throw an MdInputUnsupportedTypeError.
const EN_INPUT_INVALID_INPUT_TYPE = [
'file',
'radio',
'checkbox',
];
export class EnInputComponent {
private _focused: boolean = false;
private _value: any = '';
/** Callback registered via registerOnTouched (ControlValueAccessor) */
private _onTouchedCallback: () => void = noop;
/** Callback registered via registerOnChange (ControlValueAccessor) */
private _onChangeCallback: (_: any) => void = noop;
/**
* Aria related inputs.
*/
ariaLabel: string;
ariaLabelledBy: string;
ariaDisabled: boolean;
ariaRequired: boolean;
ariaInvalid: boolean;
// /**
// * Content directives.
// */
// @ContentChild(MdPlaceholder) _placeholderChild: MdPlaceholder;
// @ContentChildren(MdHint) _hintChildren: QueryList<MdHint>;
/** Readonly properties. */
get focused() {
return this._focused;
}
get empty() {
return this._value == null || this._value === '';
}
get characterCount(): number {
return this.empty ? 0 : ('' + this._value).length;
}
get inputId(): string {
return `${this.id}`;
}
get floatingPlaceholder(): boolean {
return this._focused || !this.empty;
}
/**
* Bindings.
*/
align: 'start' | 'end' = 'start';
// @Input() floatingPlaceholder: boolean = true;
autoComplete: string;
autoCorrect: string;
autoCapitalize: string;
autoFocus: boolean = false;
disabled: boolean = false;
id: string = ``;
list: string = null;
max: string | number = null;
maxLength: number = null;
min: string | number = null;
minLength: number = null;
placeholder: string = null;
readOnly: boolean = false;
required: boolean = false;
spellCheck: boolean = false;
step: number = null;
tabIndex: number = null;
type: string = 'text';
name: string = null;
addonRight: boolean = false;
private _blurEmitter: EventEmitter<FocusEvent> = new EventEmitter<FocusEvent>();
private _focusEmitter: EventEmitter<FocusEvent> = new EventEmitter<FocusEvent>();
get onBlur(): Observable<FocusEvent> {
return this._blurEmitter.asObservable();
}
get onFocus(): Observable<FocusEvent> {
return this._focusEmitter.asObservable();
}
get value(): any {
return this._value;
};
set value(v: any) {
v = this._convertValueForInputType(v);
if (v !== this._value) {
this._value = v;
this._onChangeCallback(v);
}
}
btnClick: EventEmitter<any> = new EventEmitter();
_btnClickHandler(): void {
this.btnClick.emit({
value: this.value
});
}
// This is to remove the `align` property of the `md-input` itself. Otherwise HTML5
// might place it as RTL when we don't want to. We still want to use `align` as an
// Input though, so we use HostBinding.
get _align(): any {
return null;
}
_inputElement: ElementRef;
/** Set focus on input */
focus() {
this._inputElement.nativeElement.focus();
}
_handleFocus(event: FocusEvent) {
this._focused = true;
this._focusEmitter.emit(event);
}
_handleBlur(event: FocusEvent) {
this._focused = false;
this._onTouchedCallback();
this._blurEmitter.emit(event);
}
_handleChange(event: Event) {
this.value = (<HTMLInputElement>event.target).value;
this._onTouchedCallback();
}
_labelClickHandler() {
if (!this.floatingPlaceholder) {
this._inputElement.nativeElement.focus();
}
}
// _hasPlaceholder(): boolean {
// return !!this.placeholder || this._placeholderChild != null;
// }
/**
* Implemented as part of ControlValueAccessor.
* TODO: internal
*/
writeValue(value: any) {
this._value = value;
}
/**
* Implemented as part of ControlValueAccessor.
* TODO: internal
*/
registerOnChange(fn: any) {
this._onChangeCallback = fn;
}
/**
* Implemented as part of ControlValueAccessor.
* TODO: internal
*/
registerOnTouched(fn: any) {
this._onTouchedCallback = fn;
}
/** TODO: internal */
ngAfterContentInit() {
this._validateConstraints();
// Trigger validation when the hint children change.
// this._hintChildren.changes.subscribe(() => {
// this._validateConstraints();
// });
}
/** TODO: internal */
ngOnChanges(changes: {[key: string]: SimpleChange}) {
this._validateConstraints();
}
/**
* Convert the value passed in to a value that is expected from the type of the md-input.
* This is normally performed by the *_VALUE_ACCESSOR in forms, but since the type is bound
* on our internal input it won't work locally.
* @private
*/
private _convertValueForInputType(v: any): any {
switch (this.type) {
case 'number':
return parseFloat(v);
default:
return v;
}
}
/**
* Ensure that all constraints defined by the API are validated, or throw errors otherwise.
* Constraints for now:
* - type attribute is not one of the forbidden types (see constant at the top).
* @private
*/
private _validateConstraints() {
if (EN_INPUT_INVALID_INPUT_TYPE.indexOf(this.type) != -1) {
throw new TypeError(`${this.type} is not a valid en-input type.`);
}
}
}