salix/front/core/components/field/index.js

228 lines
4.9 KiB
JavaScript

import ngModule from '../../module';
import FormInput from '../form-input';
import './style.scss';
export default class Field extends FormInput {
constructor($element, $scope) {
super($element, $scope);
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.input.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'];
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';
}