ngx-form-control
Version:
Form controls for angular 6
1,666 lines (1,631 loc) • 143 kB
JavaScript
import { Input, Component, ViewChild, EventEmitter, Output, NgModule } from '@angular/core';
import { NG_VALIDATORS, NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @abstract
*/
class BaseControlComponent {
constructor() {
this.id = 'ngx-' + Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
this.innerCustomErrorMessages = [];
this.name = '';
this.label = '';
this.placeholder = '';
this.title = '';
this.required = false;
this.disabled = false;
this.validMessage = '';
this.requiredErrorMessage = 'This field is required.';
}
/**
* @param {?} messages
* @return {?}
*/
set customErrorMessages(messages) {
if (!messages) {
this.innerCustomErrorMessages = [];
}
else if ('string' === typeof messages) {
this.innerCustomErrorMessages = [messages];
}
else if (messages[0]) {
this.innerCustomErrorMessages = messages;
}
else {
this.innerCustomErrorMessages = [];
}
}
/**
* @return {?}
*/
get hasCustomError() {
return !!(this.innerCustomErrorMessages && this.innerCustomErrorMessages[0]);
}
/**
* @return {?}
*/
get hasRequiredError() {
return this.required && this.value !== false && this.value !== 0 && !this.value;
}
/**
* @param {?} fn
* @return {?}
*/
registerOnChange(fn) {
this._onChangeCallback = event => {
if (this.cleanCustomErrorMessageOnChanged) {
this.innerCustomErrorMessages = [];
}
return fn(event);
};
}
/**
* @param {?} fn
* @return {?}
*/
registerOnTouched(fn) {
this._onTouchedCallback = fn;
}
/**
* @return {?}
*/
triggerChange() {
if (this._onChangeCallback) {
this._onChangeCallback(this.value);
}
}
}
BaseControlComponent.propDecorators = {
name: [{ type: Input }],
label: [{ type: Input }],
placeholder: [{ type: Input }],
title: [{ type: Input }],
required: [{ type: Input }],
disabled: [{ type: Input }],
validMessage: [{ type: Input }],
requiredErrorMessage: [{ type: Input }],
cleanCustomErrorMessageOnChanged: [{ type: Input }],
customErrorMessages: [{ type: Input }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @abstract
*/
class BaseListControlComponent extends BaseControlComponent {
constructor() {
super(...arguments);
this._options = [];
this._selectOptions = [];
this._selectedIndexes = [];
}
/**
* @param {?} value
* @return {?}
*/
set textKey(value) {
this._textKey = value;
this.initOptions();
}
/**
* @param {?} value
* @return {?}
*/
set valueKey(value) {
this._valueKey = value;
this.initOptions();
}
/**
* @param {?} value
* @return {?}
*/
set comparedKey(value) {
this._comparedKey = value;
this.initOptions();
}
/**
* @param {?} options
* @return {?}
*/
set options(options) {
this._options = options;
this.initOptions();
}
/**
* @return {?}
*/
get selectOptions() {
return this._selectOptions;
}
/**
* @return {?}
*/
get selectedIndexes() {
return this._selectedIndexes;
}
/**
* @param {?} indexes
* @return {?}
*/
set selectedIndexes(indexes) {
/** @type {?} */
const oldSelectedIndexes = JSON.stringify(this._selectedIndexes);
this._selectedIndexes = indexes && indexes.length ? indexes.reduce((arr, value) => {
value = +value;
if (value > -1) {
arr.push(value);
}
return arr;
}, []) : [];
/** @type {?} */
const newSelectedIndexes = JSON.stringify(this._selectedIndexes);
if (newSelectedIndexes !== oldSelectedIndexes) {
this.triggerChange();
}
}
/**
* @param {?} value
* @return {?}
*/
findIndex(value) {
/** @type {?} */
const comparedValue = this.getComparedValue(value);
return this._selectOptions.findIndex((option) => {
return comparedValue === option.comparedValue;
});
}
/**
* @param {?} arrValue
* @return {?}
*/
findIndexes(arrValue) {
if (!arrValue || !arrValue.length) {
return [];
}
return arrValue.reduce((arr, value) => {
/** @type {?} */
const index = this.findIndex(value);
if (index > -1) {
arr.push(index);
}
return arr;
}, []);
}
/**
* @return {?}
*/
initOptions() {
this.beforeInitOptions();
/** @type {?} */
const oldValue = this.value;
this._selectOptions = [];
if (this._options && this._options.length) {
this._options.map((option, index) => {
/** @type {?} */
let text;
/** @type {?} */
let value;
if ('string' === typeof option || 'number' === typeof option) {
text = option;
value = option;
}
else {
text = option[this._textKey || 'text'];
value = this._valueKey ? option[this._valueKey] : option;
}
this._selectOptions.push({
id: index,
text: text,
value: value,
comparedValue: this.getComparedValue(option),
});
});
}
this.afterInitOptions();
this.writeValue(oldValue);
/** @type {?} */
const newValue = this.value;
if (JSON.stringify(oldValue) !== JSON.stringify(newValue)) {
this.triggerChange();
}
}
/**
* @return {?}
*/
beforeInitOptions() {
}
/**
* @return {?}
*/
afterInitOptions() {
}
/**
* @param {?} option
* @return {?}
*/
getComparedValue(option) {
if (!option) {
return '';
}
if ('string' === typeof option || 'number' === typeof option) {
return option;
}
/** @type {?} */
let value;
if (this._comparedKey) {
value = option[this._comparedKey];
}
else {
value = this._valueKey ? option[this._valueKey] : option;
}
if ('string' === typeof value || 'number' === typeof value) {
return value;
}
return JSON.stringify(value);
}
}
BaseListControlComponent.propDecorators = {
textKey: [{ type: Input }],
valueKey: [{ type: Input }],
comparedKey: [{ type: Input }],
options: [{ type: Input }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class FormCheckboxComponent extends BaseListControlComponent {
constructor() {
super(...arguments);
this._isTouched = false;
}
/**
* @return {?}
*/
get isEmpty() {
return !this._selectedIndexes || !this._selectedIndexes.length;
}
/**
* @return {?}
*/
get value() {
return this.isEmpty ? null : this._selectedIndexes.map(index => this._selectOptions[index].value);
}
/**
* @return {?}
*/
get invalid() {
if (this.hasCustomError) {
return true;
}
if (!this._isTouched) {
return false;
}
return this.hasRequiredError;
}
/**
* @return {?}
*/
get valid() {
if (this.hasCustomError) {
return false;
}
if (!this._isTouched) {
return false;
}
return !this.hasRequiredError;
}
/**
* @return {?}
*/
get errorMessages() {
if (this.hasCustomError) {
return this.innerCustomErrorMessages;
}
if (this.hasRequiredError) {
return [this.requiredErrorMessage];
}
}
/**
* @param {?} value
* @return {?}
*/
writeValue(value) {
/** @type {?} */
const listElement = this.listRadioElement.nativeElement.querySelectorAll('.custom-control-input');
for (const element of listElement) {
element.checked = false;
}
if (!value) {
return;
}
this._selectedIndexes = this.findIndexes(value);
if (!this.listRadioElement || !this.listRadioElement.nativeElement) {
return;
}
if (this.value) {
setTimeout(() => {
this._selectedIndexes.map(index => {
listElement[index].checked = true;
});
});
}
}
/**
* @return {?}
*/
validate() {
/** @type {?} */
const result = {};
if (this.hasRequiredError) {
result['required'] = true;
}
return result;
}
/**
* @param {?} index
* @param {?} event
* @return {?}
*/
toggle(index, event) {
this._isTouched = true;
/** @type {?} */
const checked = event.target.checked;
index = +index;
if (checked) {
this._selectedIndexes.push(index);
}
else {
/** @type {?} */
const indexOfIndex = this._selectedIndexes.indexOf(index);
if (indexOfIndex > -1) {
this._selectedIndexes.splice(indexOfIndex, 1);
}
}
this.triggerChange();
}
/**
* @return {?}
*/
reset() {
this._isTouched = false;
}
}
FormCheckboxComponent.decorators = [
{ type: Component, args: [{
selector: 'ngx-form-checkbox',
template: `<label *ngIf="label" [for]="id">{{label}}</label>
<div #listRadioElement>
<div class="custom-control custom-checkbox" *ngFor="let option of selectOptions; let index = index;">
<input class="custom-control-input"
[ngClass]="{'is-invalid': invalid, 'is-valid': valid}"
type="checkbox"
[id]="id + '-' + index"
[name]="id"
(click)="toggle(index, $event)"
title="">
<label class="custom-control-label" [for]="id + '-' + index">{{option.text}}</label>
</div>
</div>
<ng-container *ngIf="valid && validMessage">
<div class="custom-control-input is-valid"></div>
<div class="valid-feedback">{{validMessage}}</div>
</ng-container>
<ng-container *ngIf="invalid">
<div class="custom-control-input is-invalid"></div>
<div class="invalid-feedback">
<span *ngFor="let message of errorMessages; let last = last;">
{{message}}<br *ngIf="!last">
</span>
</div>
</ng-container>
`,
styles: [`:host .form-check.is-valid~.invalid-feedback,:host .form-check.is-valid~.invalid-tooltip,:host .form-check.is-valid~.valid-feedback,:host .form-check.is-valid~.valid-tooltip,:host .was-validated~.invalid-feedback,:host .was-validated~.invalid-tooltip,:host .was-validated~.valid-feedback,:host .was-validated~.valid-tooltip{display:block}`],
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: FormCheckboxComponent, multi: true },
{ provide: NG_VALIDATORS, useExisting: FormCheckboxComponent, multi: true }
]
},] },
];
FormCheckboxComponent.propDecorators = {
listRadioElement: [{ type: ViewChild, args: ['listRadioElement',] }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class FormInputComponent extends BaseControlComponent {
constructor() {
super(...arguments);
this.type = 'text';
this.pattern = '';
this.readonly = false;
this.autocomplete = true;
this.trimResult = true;
this.minLengthErrorMessage = 'Value is too short.';
this.patternErrorMessage = 'Value is not valid.';
this.matchErrorMessage = 'Value does not match.';
this.focus = new EventEmitter();
this.blur = new EventEmitter();
}
/**
* @param {?} value
* @return {?}
*/
set match(value) {
this._match = value || '';
this.triggerChange();
}
/**
* @return {?}
*/
get value() {
if (!this._innerValue) {
return '';
}
if ('string' !== typeof this._innerValue) {
return this._innerValue;
}
return this.trimResult ? this._innerValue.trim() : this._innerValue;
}
/**
* @param {?} value
* @return {?}
*/
set value(value) {
if (value !== this._innerValue) {
this._innerValue = value;
this.triggerChange();
}
}
/**
* @return {?}
*/
get hasMatchError() {
return !!this._match && this._match !== this.value;
}
/**
* @return {?}
*/
get hasPatternError() {
return this.customInput.errors && this.customInput.errors['pattern'];
}
/**
* @return {?}
*/
get hasMinLengthError() {
return this.customInput.errors && this.customInput.errors['minlength'];
}
/**
* @return {?}
*/
get invalid() {
if (this.hasCustomError) {
return true;
}
if (!this.customInput.touched) {
return false;
}
return this.customInput.invalid || this.hasMatchError || this.hasRequiredError;
}
/**
* @return {?}
*/
get valid() {
if (this.hasCustomError) {
return false;
}
if (!this.customInput.touched) {
return false;
}
return !this.customInput.invalid && !this.hasMatchError && !this.hasRequiredError;
}
/**
* @return {?}
*/
get errorMessages() {
if (this.hasRequiredError) {
return [this.requiredErrorMessage];
}
if (this.hasMatchError) {
return [this.matchErrorMessage];
}
if (this.hasPatternError) {
return [this.patternErrorMessage];
}
if (this.hasMinLengthError) {
return [this.minLengthErrorMessage];
}
if (this.hasCustomError) {
return this.innerCustomErrorMessages;
}
}
/**
* @param {?} value
* @return {?}
*/
writeValue(value) {
this._innerValue = value;
}
/**
* @return {?}
*/
validate() {
/** @type {?} */
const result = this.customInput.errors || {};
if (this.hasRequiredError) {
result['required'] = true;
}
else {
delete result['required'];
}
if (this.hasMatchError) {
result['match'] = true;
}
return result;
}
/**
* @return {?}
*/
reset() {
this.customInput.reset();
}
/**
* @param {?} event
* @return {?}
*/
onFocus(event) {
this.focus.emit(event);
}
/**
* @param {?} event
* @return {?}
*/
onBlur(event) {
this.blur.emit(event);
}
}
FormInputComponent.decorators = [
{ type: Component, args: [{
selector: 'ngx-form-input',
template: `<label *ngIf="label" [for]="id">{{label}}</label>
<!--suppress HtmlFormInputWithoutLabel -->
<input class="form-control"
[ngClass]="{'is-invalid': invalid, 'is-valid': valid}"
[type]="type"
[id]="id"
[required]="required"
[disabled]="disabled"
[readonly]="readonly"
[minlength]="minlength"
[maxlength]="maxlength"
[placeholder]="placeholder"
[title]="title"
[pattern]="pattern"
[(ngModel)]="value"
(input)="triggerChange()"
[autocomplete]="autocomplete ? 'on' : 'off'"
(focus)="onFocus($event)"
(blur)="onBlur($event)"
#customInput="ngModel">
<div class="valid-feedback" *ngIf="valid && validMessage">{{validMessage}}</div>
<div class="invalid-feedback" *ngIf="invalid">
<span *ngFor="let message of errorMessages; let last = last;">
{{message}}<br *ngIf="!last">
</span>
</div>
`,
styles: [``],
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: FormInputComponent, multi: true },
{ provide: NG_VALIDATORS, useExisting: FormInputComponent, multi: true }
]
},] },
];
FormInputComponent.propDecorators = {
type: [{ type: Input }],
pattern: [{ type: Input }],
readonly: [{ type: Input }],
autocomplete: [{ type: Input }],
minlength: [{ type: Input }],
maxlength: [{ type: Input }],
trimResult: [{ type: Input }],
minLengthErrorMessage: [{ type: Input }],
patternErrorMessage: [{ type: Input }],
matchErrorMessage: [{ type: Input }],
customInput: [{ type: ViewChild, args: ['customInput',] }],
match: [{ type: Input }],
focus: [{ type: Output }],
blur: [{ type: Output }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class FormRadioComponent extends BaseListControlComponent {
constructor() {
super(...arguments);
this._isTouched = false;
}
/**
* @return {?}
*/
get isEmpty() {
return !this._selectedIndexes || !this._selectedIndexes.length;
}
/**
* @return {?}
*/
get value() {
return this.isEmpty ? null : this._selectOptions[this._selectedIndexes[0]].value;
}
/**
* @return {?}
*/
get invalid() {
if (this.hasCustomError) {
return true;
}
if (!this._isTouched) {
return false;
}
return this.hasRequiredError;
}
/**
* @return {?}
*/
get valid() {
if (this.hasCustomError) {
return false;
}
if (!this._isTouched) {
return false;
}
return !this.hasRequiredError;
}
/**
* @return {?}
*/
get errorMessages() {
if (this.hasRequiredError) {
return [this.requiredErrorMessage];
}
if (this.hasCustomError) {
return this.innerCustomErrorMessages;
}
}
/**
* @param {?} value
* @return {?}
*/
writeValue(value) {
/** @type {?} */
const listElement = this.listRadioElement.nativeElement.querySelectorAll('.custom-control-input');
for (const element of listElement) {
element.checked = false;
}
if (!value) {
return;
}
this._selectedIndexes = this.findIndexes([value]);
if (!this.listRadioElement || !this.listRadioElement.nativeElement) {
return;
}
if (this.value) {
setTimeout(() => {
/** @type {?} */
const index = this._selectedIndexes[0];
listElement[index].checked = true;
});
}
}
/**
* @return {?}
*/
validate() {
/** @type {?} */
const result = {};
if (this.hasRequiredError) {
result['required'] = true;
}
return result;
}
/**
* @param {?} index
* @param {?} event
* @return {?}
*/
toggle(index, event) {
this._isTouched = true;
index = +index;
if (this.required || index !== this._selectedIndexes[0]) {
this._selectedIndexes = [+index];
}
else {
this._selectedIndexes = [];
event.target.checked = false;
}
this.triggerChange();
}
/**
* @return {?}
*/
reset() {
this._isTouched = false;
}
}
FormRadioComponent.decorators = [
{ type: Component, args: [{
selector: 'ngx-form-radio',
template: `<label *ngIf="label" [for]="id">{{label}}</label>
<div #listRadioElement>
<div class="custom-control custom-radio" *ngFor="let option of selectOptions; let index = index;">
<input class="custom-control-input"
[ngClass]="{'is-invalid': invalid, 'is-valid': valid}"
type="radio"
[id]="id + '-' + index"
[name]="id"
(click)="toggle(index, $event)"
title="">
<label class="custom-control-label" [for]="id + '-' + index">{{option.text}}</label>
</div>
</div>
<ng-container *ngIf="valid && validMessage">
<div class="custom-control-input is-valid"></div>
<div class="valid-feedback">{{validMessage}}</div>
</ng-container>
<ng-container *ngIf="invalid">
<div class="custom-control-input is-invalid"></div>
<div class="invalid-feedback">
<span *ngFor="let message of errorMessages; let last = last;">
{{message}}<br *ngIf="!last">
</span>
</div>
</ng-container>
`,
styles: [`:host .form-check.is-valid~.invalid-feedback,:host .form-check.is-valid~.invalid-tooltip,:host .form-check.is-valid~.valid-feedback,:host .form-check.is-valid~.valid-tooltip,:host .was-validated~.invalid-feedback,:host .was-validated~.invalid-tooltip,:host .was-validated~.valid-feedback,:host .was-validated~.valid-tooltip{display:block}`],
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: FormRadioComponent, multi: true },
{ provide: NG_VALIDATORS, useExisting: FormRadioComponent, multi: true }
]
},] },
];
FormRadioComponent.propDecorators = {
listRadioElement: [{ type: ViewChild, args: ['listRadioElement',] }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class FormSelectComponent extends BaseListControlComponent {
/**
* @return {?}
*/
get multiple() {
return this._multiple;
}
/**
* @param {?} value
* @return {?}
*/
set multiple(value) {
this._multiple = value;
}
/**
* @return {?}
*/
get isEmpty() {
return !this._selectedIndexes ||
!this._selectedIndexes.length ||
(1 === this._selectedIndexes.length && -1 === this._selectedIndexes[0]);
}
/**
* @return {?}
*/
get value() {
if (this.isEmpty) {
return null;
}
if (this._multiple) {
return this._selectedIndexes.map(index => this._selectOptions[index].value);
}
else {
/** @type {?} */
const index = this._selectedIndexes[0];
return this.selectOptions[index].value;
}
}
/**
* @return {?}
*/
get invalid() {
if (this.hasCustomError) {
return true;
}
if (!this.customSelect.touched) {
return false;
}
return this.customSelect.invalid || this.hasRequiredError;
}
/**
* @return {?}
*/
get valid() {
if (this.hasCustomError) {
return false;
}
if (!this.customSelect.touched) {
return false;
}
return !this.customSelect.invalid && !this.hasRequiredError;
}
/**
* @return {?}
*/
get errorMessages() {
if (this.hasRequiredError) {
return [this.requiredErrorMessage];
}
if (this.hasCustomError) {
return this.innerCustomErrorMessages;
}
}
/**
* @param {?} value
* @return {?}
*/
writeValue(value) {
if (!this.multiple) {
value = [value];
}
this._selectedIndexes = this.findIndexes(value);
}
/**
* @return {?}
*/
validate() {
/** @type {?} */
const result = this.customSelect.errors || {};
if (this.hasRequiredError) {
result['required'] = true;
}
else {
delete result['required'];
}
return result;
}
/**
* @return {?}
*/
reset() {
this.customSelect.reset();
}
}
FormSelectComponent.decorators = [
{ type: Component, args: [{
selector: 'ngx-form-select',
template: `<label *ngIf="label" [for]="id">{{label}}</label>
<!--suppress HtmlFormInputWithoutLabel -->
<select class="form-control"
[ngClass]="{'is-invalid': invalid, 'is-valid': valid}"
[id]="id"
[title]="title"
[required]="required"
[disabled]="disabled"
[multiple]="multiple"
[(ngModel)]="selectedIndexes"
#customSelect="ngModel"
#customSelectElement>
<option value="-1" *ngIf="placeholder">{{placeholder}}</option>
<option *ngFor="let option of selectOptions; let index = index;" [value]="index">{{option.text}}</option>
</select>
<div class="valid-feedback" *ngIf="valid && validMessage">{{validMessage}}</div>
<div class="invalid-feedback" *ngIf="invalid">
<span *ngFor="let message of errorMessages; let last = last;">
{{message}}<br *ngIf="!last">
</span>
</div>
`,
styles: [``],
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: FormSelectComponent, multi: true },
{ provide: NG_VALIDATORS, useExisting: FormSelectComponent, multi: true }
]
},] },
];
FormSelectComponent.propDecorators = {
customSelect: [{ type: ViewChild, args: ['customSelect',] }],
customSelectElement: [{ type: ViewChild, args: ['customSelectElement',] }],
multiple: [{ type: Input }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class Common {
/**
* @return {?}
*/
static isClient() {
return 'undefined' !== typeof window;
}
/**
* @return {?}
*/
static isServer() {
return 'undefined' === typeof window;
}
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class FormSelect2Component extends BaseListControlComponent {
constructor() {
super(...arguments);
this._isTouched = false;
}
/**
* @param {?} value
* @return {?}
*/
set placeholder(value) {
this._placeholder = value;
this.updateSelect2Options();
}
/**
* @param {?} value
* @return {?}
*/
set required(value) {
this._required = value;
this.updateSelect2Options();
}
/**
* @param {?} value
* @return {?}
*/
set disabled(value) {
this._disabled = value;
this.updateSelect2Options();
}
/**
* @param {?} value
* @return {?}
*/
set multiple(value) {
this._multiple = value;
this.updateSelect2Options();
}
/**
* @param {?} value
* @return {?}
*/
set tag(value) {
this._tag = value;
this.updateSelect2Options();
}
/**
* @param {?} value
* @return {?}
*/
set tokenSeparators(value) {
this._tag = value;
this.updateSelect2Options();
}
/**
* @return {?}
*/
get value() {
if (!this._selectedIndexes || !this._selectedIndexes.length) {
return null;
}
/** @type {?} */
const result = this._selectedIndexes.reduce((currentResult, index) => {
if (Number.isInteger(index) && this._selectOptions[index]) {
currentResult.push(this._selectOptions[index].value);
}
else if (this._tag) {
/** @type {?} */
const match = index['value'].match(/^number: {([\d]+)}$/);
if (match) {
currentResult.push(match[1]);
}
else {
currentResult.push(index['value']);
}
}
return currentResult;
}, []);
return this._multiple ? result : result[0];
}
/**
* @return {?}
*/
get invalid() {
if (this.hasCustomError) {
return true;
}
if (!this._isTouched) {
return false;
}
return this.hasRequiredError;
}
/**
* @return {?}
*/
get valid() {
if (this.hasCustomError) {
return false;
}
if (!this._isTouched) {
return false;
}
return !this.hasRequiredError;
}
/**
* @return {?}
*/
get errorMessages() {
if (this.hasRequiredError) {
return [this.requiredErrorMessage];
}
if (this.hasCustomError) {
return this.innerCustomErrorMessages;
}
}
/**
* @return {?}
*/
ngOnInit() {
this.updateSelect2Options();
}
/**
* @param {?} value
* @return {?}
*/
writeValue(value) {
if (this._multiple && value && value.length) {
this.selectValues(value);
}
else if (!this._multiple) {
this.selectValue(value);
}
else {
this.cleanValue();
}
}
/**
* @return {?}
*/
validate() {
/** @type {?} */
const result = {};
if (this.hasRequiredError) {
result['required'] = true;
}
return result;
}
/**
* @return {?}
*/
reset() {
this._isTouched = false;
}
/**
* @return {?}
*/
afterInitOptions() {
this._selectOptions = [...this._selectOptions];
this.updateSelect2Options();
}
/**
* @param {?} values
* @return {?}
*/
selectValues(values) {
this._selectedIndexes = [];
/** @type {?} */
const select2Data = [];
if (values && values.length) {
values.map((value) => {
/** @type {?} */
const index = this.findIndex(value);
if (index > -1) {
this._selectedIndexes.push(index);
select2Data.push(index);
}
else if (this._tag) {
this._selectedIndexes.push({ value });
select2Data.push(value);
}
});
}
if (Common.isClient()) {
this._selectElement.val(select2Data);
this._selectElement.trigger('change');
}
}
/**
* @return {?}
*/
updateSelectedIndexes() {
if (Common.isServer()) {
return;
}
/** @type {?} */
const oldSelectedIndexes = JSON.stringify(this._selectedIndexes);
/** @type {?} */
const value = this._selectElement.val();
if ('number' === typeof value || ('string' === typeof value && Number.isInteger(+value))) {
this._selectedIndexes = [+value];
}
else if ('string' === typeof value && this._tag) {
this._selectedIndexes = [{ value }];
}
else if (value && value.length) {
this._selectedIndexes = value.map(item => {
if (Number.isInteger(+item)) {
return +item;
}
if (this._tag) {
return { value: item };
}
return null;
});
}
else {
this._selectedIndexes = [];
}
/** @type {?} */
const newSelectedIndexes = JSON.stringify(this._selectedIndexes);
if (newSelectedIndexes !== oldSelectedIndexes) {
this.triggerChange();
}
}
/**
* @param {?} value
* @return {?}
*/
selectValue(value) {
if (Common.isServer()) {
return;
}
/** @type {?} */
const index = this.findIndex(value);
if (index > -1) {
this._selectedIndexes = [index];
this._selectElement.val(this._selectedIndexes);
this._selectElement.trigger('change');
}
else if (this._tag) {
this._selectedIndexes = [{ value }];
this._selectElement.val(value);
this._selectElement.trigger('change');
}
else {
this.cleanValue();
}
}
/**
* @return {?}
*/
cleanValue() {
if (Common.isServer()) {
return;
}
this._selectedIndexes = [];
this._selectElement.val(null);
this._selectElement.trigger('change');
}
/**
* @return {?}
*/
updateSelect2Options() {
if (Common.isServer() || !this.customSelectElement || !this.customSelectElement.nativeElement) {
return;
}
this._selectElement = $(this.customSelectElement.nativeElement);
if (this._selectElement.hasClass('select2-hidden-accessible')) {
this._selectElement.select2().empty();
this._selectElement.select2('destroy');
}
this._selectElement.select2({
tags: this._tag,
tokenSeparators: this._tokenSeparators || [],
placeholder: this._placeholder,
allowClear: !this._required,
multiple: this._multiple,
data: this._selectOptions,
disabled: this._disabled,
createTag: function (params) {
/** @type {?} */
const term = $.trim(params.term);
if (term === '') {
return null;
}
return {
id: Number.isInteger(+term) ? `number: {${term}}` : term,
text: term,
newTag: true
};
}
});
this._selectElement.on('select2:select', () => {
this.updateSelectedIndexes();
});
this._selectElement.on('select2:unselect', () => {
this.updateSelectedIndexes();
});
this._selectElement.on('select2:close', () => {
this._isTouched = true;
});
}
}
FormSelect2Component.decorators = [
{ type: Component, args: [{
selector: 'ngx-form-select2',
template: `<label *ngIf="label" [for]="id">{{label}}</label>
<div class="form-control is-invalid" [ngClass]="{'is-invalid': invalid, 'is-valid': valid}">
<!--suppress HtmlFormInputWithoutLabel -->
<select [id]="id" #customSelectElement></select>
</div>
<div class="valid-feedback" *ngIf="valid && validMessage">{{validMessage}}</div>
<div class="invalid-feedback" *ngIf="invalid">
<span *ngFor="let message of errorMessages; let last = last;">
{{message}}<br *ngIf="!last">
</span>
</div>
`,
styles: [`:host .form-control{padding:0}:host .form-control /deep/ .select2-container{width:100%!important}:host .form-control /deep/ .select2-container .select2-selection--single{height:auto}:host .form-control /deep/ .select2-container--default .select2-selection--multiple,:host .form-control /deep/ .select2-container--default .select2-selection--single,:host .form-control /deep/ .select2-container--default.select2-container--focus .select2-selection--multiple{border:none;outline:0!important}:host .form-control /deep/ .select2-container--default .select2-selection--multiple:focus,:host .form-control /deep/ .select2-container--default .select2-selection--single:focus{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}:host .form-control.is-invalid /deep/ .select2-container--default .select2-selection--multiple:focus,:host .form-control.is-invalid /deep/ .select2-container--default .select2-selection--single:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}:host .form-control.is-valid /deep/ .select2-container--default .select2-selection--multiple:focus,:host .form-control.is-valid /deep/ .select2-container--default .select2-selection--single:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}:host .form-control /deep/ .select2-container--default .select2-selection--single .select2-selection__rendered{min-height:40px;line-height:25px;padding:.375rem 25px .375rem .75rem}:host .form-control /deep/ .select2-container .select2-selection--multiple{min-height:40px;padding:.375rem .75rem}:host .form-control /deep/ .select2-container--default .select2-selection--multiple .select2-selection__rendered{padding:0}:host .form-control /deep/ .select2-container--default .select2-selection--single .select2-selection__arrow{height:38px}`],
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: FormSelect2Component, multi: true },
{ provide: NG_VALIDATORS, useExisting: FormSelect2Component, multi: true }
]
},] },
];
FormSelect2Component.propDecorators = {
customSelectElement: [{ type: ViewChild, args: ['customSelectElement',] }],
placeholder: [{ type: Input }],
required: [{ type: Input }],
disabled: [{ type: Input }],
multiple: [{ type: Input }],
tag: [{ type: Input }],
tokenSeparators: [{ type: Input }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class FormTextareaComponent extends BaseControlComponent {
constructor() {
super(...arguments);
this.rows = 5;
this.readonly = false;
this.trimResult = true;
this.minLengthErrorMessage = 'Value is too short.';
}
/**
* @return {?}
*/
get value() {
if (!this._innerValue) {
return '';
}
if ('string' !== typeof this._innerValue) {
return this._innerValue;
}
return this.trimResult ? this._innerValue.trim() : this._innerValue;
}
/**
* @param {?} value
* @return {?}
*/
set value(value) {
if (value !== this._innerValue) {
this._innerValue = value;
this.triggerChange();
}
}
/**
* @return {?}
*/
get hasMinLengthError() {
return this.customTextarea.errors && this.customTextarea.errors['minlength'];
}
/**
* @return {?}
*/
get invalid() {
if (this.hasCustomError) {
return true;
}
if (!this.customTextarea.touched) {
return false;
}
return this.customTextarea.invalid || this.hasRequiredError;
}
/**
* @return {?}
*/
get valid() {
if (this.hasCustomError) {
return false;
}
if (!this.customTextarea.touched) {
return false;
}
return !this.customTextarea.invalid && !this.hasRequiredError;
}
/**
* @return {?}
*/
get errorMessages() {
if (this.hasRequiredError) {
return [this.requiredErrorMessage];
}
if (this.hasMinLengthError) {
return [this.minLengthErrorMessage];
}
if (this.hasCustomError) {
return this.innerCustomErrorMessages;
}
}
/**
* @param {?} value
* @return {?}
*/
writeValue(value) {
this._innerValue = value;
}
/**
* @return {?}
*/
validate() {
/** @type {?} */
const result = this.customTextarea.errors || {};
if (this.hasRequiredError) {
result['required'] = true;
}
else {
delete result['required'];
}
return result;
}
/**
* @return {?}
*/
reset() {
this.customTextarea.reset();
}
}
FormTextareaComponent.decorators = [
{ type: Component, args: [{
selector: 'ngx-form-textarea',
template: `<label *ngIf="label" [for]="id">{{label}}</label>
<!--suppress HtmlFormInputWithoutLabel -->
<textarea class="form-control"
[ngClass]="{'is-invalid': invalid, 'is-valid': valid}"
[id]="id"
[title]="title"
[required]="required"
[disabled]="disabled"
[readonly]="readonly"
[minlength]="minlength"
[maxlength]="maxlength"
[placeholder]="placeholder"
[(ngModel)]="value"
[rows]="rows"
#customTextarea="ngModel"></textarea>
<div class="valid-feedback" *ngIf="valid && validMessage">{{validMessage}}</div>
<div class="invalid-feedback" *ngIf="invalid">
<span *ngFor="let message of errorMessages; let last = last;">
{{message}}<br *ngIf="!last">
</span>
</div>
`,
styles: [``],
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: FormTextareaComponent, multi: true },
{ provide: NG_VALIDATORS, useExisting: FormTextareaComponent, multi: true }
]
},] },
];
FormTextareaComponent.propDecorators = {
rows: [{ type: Input }],
readonly: [{ type: Input }],
minlength: [{ type: Input }],
maxlength: [{ type: Input }],
trimResult: [{ type: Input }],
minLengthErrorMessage: [{ type: Input }],
customTextarea: [{ type: ViewChild, args: ['customTextarea',] }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class FormToggleComponent extends BaseControlComponent {
constructor() {
super(...arguments);
this.type = 'checkbox';
this._innerValue = false;
this._isTouch = false;
}
/**
* @return {?}
*/
get value() {
return this._innerValue;
}
/**
* @param {?} value
* @return {?}
*/
set value(value) {
this._isTouch = true;
this._innerValue = value;
this.triggerChange();
}
/**
* @return {?}
*/
get invalid() {
if (this.hasCustomError) {
return true;
}
if (!this._isTouch) {
return false;
}
return this.hasRequiredError;
}
/**
* @return {?}
*/
get valid() {
if (this.hasCustomError) {
return false;
}
if (!this._isTouch) {
return false;
}
return !this.hasRequiredError;
}
/**
* @return {?}
*/
get errorMessages() {
if (this.hasRequiredError) {
return [this.requiredErrorMessage];
}
if (this.hasCustomError) {
return this.innerCustomErrorMessages;
}
}
/**
* @return {?}
*/
get isCheckboxType() {
return 'checkbox' === this.type;
}
/**
* @return {?}
*/
get isToggleType() {
return !this.isCheckboxType;
}
/**
* @param {?} value
* @return {?}
*/
writeValue(value) {
this._innerValue = value;
}
/**
* @return {?}
*/
validate() {
/** @type {?} */
const result = {};
if (this.hasRequiredError) {
result['required'] = true;
}
return result;
}
/**
* @return {?}
*/
reset() {
this._isTouch = false;
}
}
FormToggleComponent.decorators = [
{ type: Component, args: [{
selector: 'ngx-form-toggle',
template: `<div class="custom-checkbox" [ngClass]="{'custom-control': isCheckboxType}">
<ng-container *ngIf="isCheckboxType">
<!--suppress HtmlFormInputWithoutLabel -->
<input class="custom-control-input"
[title]="title"
[ngClass]="{'is-invalid': invalid, 'is-valid': valid}"
type="checkbox"
[id]="id"
[required]="required"
[(ngModel)]="value">
<label class="custom-control-label" [for]="id">{{label}}</label>
</ng-container>
<ng-container *ngIf="isToggleType">
<input class="custom-control-input tgl tgl-light"
[title]="title"
[ngClass]="{'is-invalid': invalid, 'is-valid': valid}"
type="checkbox"
[id]="id"
[required]="required"
[(ngModel)]="value">
<label class="tgl-btn" [for]="id"></label>
<label class="tgl-label" [for]="id" *ngIf="label">{{label}}</label>
</ng-container>
<div class="valid-feedback" *ngIf="valid && validMessage">{{validMessage}}</div>
<div class="invalid-feedback" *ngIf="errorMessages && errorMessages.length">
<span *ngFor="let message of errorMessages; let last = last;">
{{message}}<br *ngIf="!last">
</span>
</div>
</div>
`,
styles: [`.tgl{display:none}.tgl,.tgl *,.tgl :after,.tgl :before,.tgl+.tgl-btn,.tgl:after,.tgl:before{box-sizing:border-box}.tgl ::-moz-selection,.tgl :after::-moz-selection,.tgl :before::-moz-selection,.tgl+.tgl-btn::-moz-selection,.tgl::-moz-selection,.tgl:after::-moz-selection,.tgl:before::-moz-selection{background:0 0}.tgl ::selection,.tgl :after::selection,.tgl :before::selection,.tgl+.tgl-btn::selection,.tgl::selection,.tgl:after::selection,.tgl:before::selection{background:0 0}.tgl+.tgl-btn{outline:0;display:inline-block;vertical-align:middle;margin-right:15px;width:4em;height:2em;position:relative;cursor:pointer;margin-bottom:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.tgl+.tgl-btn:after,.tgl+.tgl-btn:before{position:relative;display:block;content:"";width:50%;height:100%}.tgl+.tgl-btn:after{left:0}.tgl+.tgl-btn:before{display:none}.tgl:checked+.tgl-btn:after{left:50%}.tgl-light+.tgl-btn{background:#f0f0f0;border-radius:2em;padding:2px;transition:all .4s ease}.tgl-light+.tgl-btn:after{border-radius:50%;background:#fff;transition:all .2s ease}.tgl-light:checked+.tgl-btn{background:#9fd6ae}.custom-control-input~.tgl-label{margin-bottom:0;vertical-align:middle}.custom-control-input.is-invalid~.tgl-label{color:#dc3545}.custom-control-input.is-valid~.tgl-label{color:#28a745}`],
providers: [
{ provide: NG_VALUE_ACCESSOR, useExisting: FormToggleComponent, multi: true },
{ provide: NG_VALIDATORS, useExisting: FormToggleComponent, multi: true }
]
},] },
];
FormToggleComponent.propDecorators = {
type: [{ type: Input }]
};
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
class FormControlModule {
}
FormControlModule.decorators = [
{ type: NgModule, args: [{
imports: [
BrowserModule,
FormsModule,
],
declarations: [
FormCheckboxComponent,
FormInputComponent,
FormRadioComponent,
FormSelectComponent,
FormSelect2Component,
FormTextareaComponent,
FormToggleComponent,
],
exports: [
FormCheckboxComponent,
FormInputComponent,
FormRadioComponent,
FormSelectComponent,
FormSelect2Component,
FormTextareaComponent,
FormToggleComponent,
]
},] },
];
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
*/
export { FormCheckboxComponent, FormInputComponent, FormRadioComponent, FormSelectComponent, FormSelect2Component, FormTextareaComponent, FormToggleComponent, FormControlModule, BaseControlComponent