228 lines
5.0 KiB
JavaScript
228 lines
5.0 KiB
JavaScript
import ngModule from '../../module';
|
|
import FormInput from '../form-input';
|
|
import './style.scss';
|
|
|
|
export default class Field extends FormInput {
|
|
constructor($element, $scope, $transclude) {
|
|
super($element, $scope, $transclude);
|
|
|
|
this.prefix = null;
|
|
this.suffix = null;
|
|
|
|
this.container = this.element.querySelector('.container');
|
|
this.container.addEventListener('focusout', () => this.onFocus(false));
|
|
this.container.addEventListener('focusin', () => this.onFocus(true));
|
|
|
|
this.control = this.element.querySelector('.control');
|
|
}
|
|
|
|
$onInit() {
|
|
super.$onInit();
|
|
|
|
if (this.info) this.classList.add('has-icons');
|
|
this.element.addEventListener('change', event =>
|
|
this.onChange(event));
|
|
}
|
|
|
|
set field(value) {
|
|
if (value === this.field) return;
|
|
super.field = value;
|
|
this.classList.toggle('not-empty', value != null && value !== '');
|
|
this.validateValue();
|
|
}
|
|
|
|
get field() {
|
|
return super.field;
|
|
}
|
|
|
|
set input(value) {
|
|
if (this.input)
|
|
this.control.removeChild(this.input);
|
|
this._input = value;
|
|
if (value)
|
|
this.control.appendChild(value);
|
|
}
|
|
|
|
get input() {
|
|
return this._input;
|
|
}
|
|
|
|
set value(value) {
|
|
this.input.value = value;
|
|
}
|
|
|
|
get value() {
|
|
return this.input.value;
|
|
}
|
|
|
|
set type(value) {
|
|
this.input.type = value;
|
|
}
|
|
|
|
get type() {
|
|
return this.input.type;
|
|
}
|
|
|
|
set name(value) {
|
|
this.input.name = value;
|
|
}
|
|
|
|
get name() {
|
|
return this.input.name;
|
|
}
|
|
|
|
set placeholder(value) {
|
|
this.input.placeholder = value;
|
|
}
|
|
|
|
get placeholder() {
|
|
return this.input.placeholder;
|
|
}
|
|
|
|
set required(value) {
|
|
this._required = value;
|
|
let required = this.element.querySelector('.required');
|
|
display(required, this._required);
|
|
}
|
|
|
|
get required() {
|
|
return this._required;
|
|
}
|
|
|
|
set prefix(value) {
|
|
this._prefix = value;
|
|
this.refreshFix('.prefix', value);
|
|
}
|
|
|
|
get prefix() {
|
|
return this._prefix;
|
|
}
|
|
|
|
set suffix(value) {
|
|
this._suffix = value;
|
|
this.refreshFix('.suffix', value);
|
|
}
|
|
|
|
get suffix() {
|
|
return this._suffix;
|
|
}
|
|
|
|
set hint(value) {
|
|
this._hint = value;
|
|
this.refreshHint();
|
|
}
|
|
|
|
get hint() {
|
|
return this._hint;
|
|
}
|
|
|
|
set error(value) {
|
|
if (value === this.error) return;
|
|
this._error = value;
|
|
this.refreshHint();
|
|
}
|
|
|
|
get error() {
|
|
return this._error;
|
|
}
|
|
|
|
get shownError() {
|
|
return this.error || this.inputError || null;
|
|
}
|
|
|
|
get autocomplete() {
|
|
return this._autocomplete;
|
|
}
|
|
|
|
set autocomplete(value) {
|
|
this._autocomplete = value;
|
|
|
|
if (value === 'off')
|
|
this.input.setAttribute('autocomplete', 'off');
|
|
}
|
|
|
|
refreshHint() {
|
|
let error = this.shownError;
|
|
let hint = error || this.hint;
|
|
|
|
let hintEl = this.element.querySelector('.hint');
|
|
hintEl.innerText = hint || '';
|
|
hintEl.classList.toggle('filled', Boolean(hint));
|
|
|
|
this.classList.toggle('invalid', Boolean(error));
|
|
}
|
|
|
|
refreshFix(selector, text) {
|
|
let fix = this.element.querySelector(selector);
|
|
display(fix, text);
|
|
fix.innerText = text || '';
|
|
}
|
|
|
|
onFocus(hasFocus) {
|
|
this.classList.toggle('focused', hasFocus);
|
|
}
|
|
|
|
onClear(event) {
|
|
if (event.defaultPrevented) return;
|
|
event.preventDefault();
|
|
this.field = null;
|
|
this.element.dispatchEvent(new Event('change'));
|
|
}
|
|
|
|
buildInput(type) {
|
|
let template = `<input type="${type}" ng-model="$ctrl.field"></input>`;
|
|
this.input = this.$compile(template)(this.$)[0];
|
|
}
|
|
|
|
/**
|
|
* If input value is invalid, sets the error message as hint.
|
|
*/
|
|
validateValue() {
|
|
let error = this.input.checkValidity()
|
|
? null
|
|
: this.input.validationMessage;
|
|
|
|
if (error === this.inputError) return;
|
|
this.inputError = error;
|
|
this.refreshHint();
|
|
}
|
|
|
|
onChange($event) {
|
|
// Changes doesn't reflect until appling async
|
|
this.$.$applyAsync(() => {
|
|
this.emit('change', {
|
|
value: this.field,
|
|
$event: $event
|
|
});
|
|
});
|
|
}
|
|
}
|
|
Field.$inject = ['$element', '$scope', '$transclude'];
|
|
|
|
ngModule.vnComponent('vnField', {
|
|
template: require('./index.html'),
|
|
transclude: {
|
|
prepend: '?prepend',
|
|
append: '?append'
|
|
},
|
|
controller: Field,
|
|
bindings: {
|
|
type: '@?',
|
|
autocomplete: '@?',
|
|
placeholder: '@?',
|
|
clearDisabled: '<?',
|
|
value: '=?',
|
|
info: '@?',
|
|
required: '<?',
|
|
prefix: '@?',
|
|
suffix: '@?',
|
|
hint: '@?',
|
|
error: '<?',
|
|
rule: '@?'
|
|
}
|
|
});
|
|
|
|
function display(element, display) {
|
|
element.style.display = display ? 'initial' : 'none';
|
|
}
|