@igo2/common
Version:
819 lines (803 loc) • 56 kB
JavaScript
import * as i0 from '@angular/core';
import { EventEmitter, ViewChild, Output, Input, ChangeDetectionStrategy, Component, NgModule, Injectable, ChangeDetectorRef, Inject } from '@angular/core';
import { NgClass, NgFor, NgIf, AsyncPipe } from '@angular/common';
import * as i3 from '@angular/forms';
import { FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { t } from 'typy';
import { __decorate, __metadata } from 'tslib';
import { MatOptionModule } from '@angular/material/core';
import * as i1 from '@angular/material/form-field';
import { MatFormFieldModule } from '@angular/material/form-field';
import * as i4 from '@angular/material/icon';
import { MatIconModule } from '@angular/material/icon';
import * as i2 from '@angular/material/select';
import { MatSelectModule } from '@angular/material/select';
import * as i1$1 from '@igo2/core/language';
import { IgoLanguageModule } from '@igo2/core/language';
import { BehaviorSubject } from 'rxjs';
import * as i5 from '@ngx-translate/core';
import * as i5$1 from '@angular/material/button';
import { MatButtonModule } from '@angular/material/button';
import * as i2$1 from '@angular/material/input';
import { MatInputModule } from '@angular/material/input';
import { DynamicOutletComponent } from '@igo2/common/dynamic-component';
import * as i2$2 from '@angular/material/dialog';
import { MAT_DIALOG_DATA, MatDialogTitle, MatDialogActions, MatDialogModule } from '@angular/material/dialog';
import { CustomHtmlComponent } from '@igo2/common/custom-html';
function formControlIsRequired(control) {
if (control.validator) {
const validator = control.validator({});
if (validator && validator.required) {
return true;
}
}
if (control.controls) {
const requiredControl = Object.keys(control.controls).find((key) => {
return formControlIsRequired(control.controls[key]);
});
return requiredControl !== undefined;
}
return false;
}
function getDefaultErrorMessages() {
return {
required: 'igo.common.form.errors.required',
email: 'igo.common.form.errors.email'
};
}
function getControlErrorMessage(control, messages) {
const errors = control.errors || {};
const errorKeys = Object.keys(errors);
const errorMessages = errorKeys
.map((key) => messages[key])
.filter((message) => message !== undefined);
return errorMessages.length > 0 ? errorMessages[0] : '';
}
function getAllFormFields(form) {
return form.groups.reduce((acc, group) => {
return acc.concat(group.fields);
}, [].concat(form.fields));
}
function getFormFieldByName(form, name) {
const fields = getAllFormFields(form);
return fields.find((field) => {
return field.name === name;
});
}
/**
* A configurable form
*/
class FormComponent {
/**
* Form
*/
form;
/**
* Input data
*/
formData;
/**
* Form autocomplete
*/
autocomplete = 'off';
/**
* Event emitted when the form is submitted
*/
submitForm = new EventEmitter();
buttons;
get hasButtons() {
return this.buttons.nativeElement.children.length !== 0;
}
/**
* Is the entity or the template change, recreate the form or repopulate it.
* @internal
*/
ngOnChanges(changes) {
const formData = changes.formData;
if (formData.firstChange && formData.currentValue == null) {
return;
}
if (formData && formData.currentValue !== formData.previousValue) {
if (formData.currentValue === undefined) {
this.clear();
}
else {
this.setData(formData.currentValue);
}
}
}
/**
* Transform the form data to a feature and emit an event
* @param event Form submit event
* @internal
*/
onSubmit() {
this.submitForm.emit(this.getData());
}
getData() {
const data = {};
getAllFormFields(this.form).forEach((field) => {
this.updateDataWithFormField(data, field);
});
return data;
}
setData(data) {
this.form.fields.forEach((field) => {
field.control.setValue(t(data, field.name).safeObject);
});
this.form.groups.forEach((group) => {
group.fields.forEach((field) => {
field.control.setValue(t(data, field.name).safeObject);
});
});
}
updateDataWithFormField(data, field) {
const control = field.control;
if (!control.disabled) {
data[field.name] = control.value;
}
}
/**
* Clear form
*/
clear() {
this.form.control.reset();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: FormComponent, isStandalone: true, selector: "igo-form", inputs: { form: "form", formData: "formData", autocomplete: "autocomplete" }, outputs: { submitForm: "submitForm" }, viewQueries: [{ propertyName: "buttons", first: true, predicate: ["buttons"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<form\n [autocomplete]=\"autocomplete\"\n [formGroup]=\"form.control\"\n (ngSubmit)=\"onSubmit()\"\n>\n <div\n class=\"igo-form-body\"\n [ngClass]=\"{ 'igo-form-body-with-buttons': hasButtons }\"\n >\n <div class=\"igo-form-content\">\n <ng-content></ng-content>\n </div>\n <div #buttons class=\"igo-form-buttons\">\n <ng-content select=\"[formButtons]\"></ng-content>\n </div>\n </div>\n</form>\n", styles: [":host{display:block}form{width:100%;height:100%}.igo-form-body,.igo-form-content{height:100%}.igo-form-body-with-buttons .igo-form-content{height:calc(100% - 56px)}.igo-form-content{display:flex}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormComponent, decorators: [{
type: Component,
args: [{ selector: 'igo-form', changeDetection: ChangeDetectionStrategy.OnPush, imports: [FormsModule, ReactiveFormsModule, NgClass], template: "<form\n [autocomplete]=\"autocomplete\"\n [formGroup]=\"form.control\"\n (ngSubmit)=\"onSubmit()\"\n>\n <div\n class=\"igo-form-body\"\n [ngClass]=\"{ 'igo-form-body-with-buttons': hasButtons }\"\n >\n <div class=\"igo-form-content\">\n <ng-content></ng-content>\n </div>\n <div #buttons class=\"igo-form-buttons\">\n <ng-content select=\"[formButtons]\"></ng-content>\n </div>\n </div>\n</form>\n", styles: [":host{display:block}form{width:100%;height:100%}.igo-form-body,.igo-form-content{height:100%}.igo-form-body-with-buttons .igo-form-content{height:calc(100% - 56px)}.igo-form-content{display:flex}\n"] }]
}], propDecorators: { form: [{
type: Input
}], formData: [{
type: Input
}], autocomplete: [{
type: Input
}], submitForm: [{
type: Output
}], buttons: [{
type: ViewChild,
args: ['buttons', { static: true }]
}] } });
/**
* @deprecated import the FormComponent directly
*/
class IgoFormFormModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: IgoFormFormModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.15", ngImport: i0, type: IgoFormFormModule, imports: [FormComponent], exports: [FormComponent] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: IgoFormFormModule, imports: [FormComponent] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: IgoFormFormModule, decorators: [{
type: NgModule,
args: [{
imports: [FormComponent],
exports: [FormComponent]
}]
}] });
/**
* Service where all available form fields are registered.
*/
class FormFieldService {
static fields = {};
static register(type, component) {
FormFieldService.fields[type] = component;
}
/**
* Return field component by type
* @param type Field type
* @returns Field component
*/
getFieldByType(type) {
return FormFieldService.fields[type];
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormFieldService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormFieldService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormFieldService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}] });
function IgoFormFieldComponent(type) {
return (compType) => {
FormFieldService.register(type, compType);
};
}
/**
* This component renders a select field
*/
let FormFieldSelectComponent = class FormFieldSelectComponent {
disabled$ = new BehaviorSubject(false);
/**
* Select input choices
*/
set choices(value) {
this.choices$.next(value);
}
get choices() {
return this.choices$.value;
}
choices$ = new BehaviorSubject([]);
/**
* If the select allow multiple selections
*/
multiple = false;
/**
* The field's form control
*/
formControl;
/**
* Field placeholder
*/
placeholder;
/**
* Field placeholder
*/
errors;
/**
* Wheter a disable switch should be available
*/
disableSwitch = false;
/**
* Whether the field is required
*/
get required() {
return formControlIsRequired(this.formControl);
}
ngOnInit() {
this.disabled$.next(this.formControl.disabled);
}
/**
* Get error message
*/
getErrorMessage() {
return getControlErrorMessage(this.formControl, this.errors);
}
onDisableSwitchClick() {
this.toggleDisabled();
}
toggleDisabled() {
const disabled = !this.disabled$.value;
if (disabled === true) {
this.formControl.disable();
}
else {
this.formControl.enable();
}
this.disabled$.next(disabled);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormFieldSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: FormFieldSelectComponent, isStandalone: true, selector: "igo-form-field-select", inputs: { choices: "choices", multiple: "multiple", formControl: "formControl", placeholder: "placeholder", errors: "errors", disableSwitch: "disableSwitch" }, ngImport: i0, template: "<mat-form-field>\n <mat-select\n [multiple]=\"multiple\"\n [required]=\"required\"\n [placeholder]=\"placeholder | translate\"\n [formControl]=\"formControl\"\n >\n <mat-option *ngFor=\"let choice of choices$ | async\" [value]=\"choice.value\">\n {{ choice.title }}\n </mat-option>\n </mat-select>\n <mat-icon\n *ngIf=\"disableSwitch === true\"\n class=\"igo-form-disable-switch\"\n (click)=\"onDisableSwitchClick()\"\n matPrefix\n >{{\n (disabled$ | async) === true ? 'check_box_outline_blank' : 'check_box'\n }}\n </mat-icon>\n <mat-error *ngIf=\"formControl.errors\">{{\n getErrorMessage() | translate\n }}</mat-error>\n</mat-form-field>\n", dependencies: [{ kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i1.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i2.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: MatOptionModule }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "ngmodule", type: IgoLanguageModule }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
};
FormFieldSelectComponent = __decorate([
IgoFormFieldComponent('select')
], FormFieldSelectComponent);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormFieldSelectComponent, decorators: [{
type: Component,
args: [{ selector: 'igo-form-field-select', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
MatFormFieldModule,
MatSelectModule,
FormsModule,
ReactiveFormsModule,
NgFor,
MatOptionModule,
NgIf,
MatIconModule,
AsyncPipe,
IgoLanguageModule
], template: "<mat-form-field>\n <mat-select\n [multiple]=\"multiple\"\n [required]=\"required\"\n [placeholder]=\"placeholder | translate\"\n [formControl]=\"formControl\"\n >\n <mat-option *ngFor=\"let choice of choices$ | async\" [value]=\"choice.value\">\n {{ choice.title }}\n </mat-option>\n </mat-select>\n <mat-icon\n *ngIf=\"disableSwitch === true\"\n class=\"igo-form-disable-switch\"\n (click)=\"onDisableSwitchClick()\"\n matPrefix\n >{{\n (disabled$ | async) === true ? 'check_box_outline_blank' : 'check_box'\n }}\n </mat-icon>\n <mat-error *ngIf=\"formControl.errors\">{{\n getErrorMessage() | translate\n }}</mat-error>\n</mat-form-field>\n" }]
}], propDecorators: { choices: [{
type: Input
}], multiple: [{
type: Input
}], formControl: [{
type: Input
}], placeholder: [{
type: Input
}], errors: [{
type: Input
}], disableSwitch: [{
type: Input
}] } });
/**
* This component renders a text field
*/
let FormFieldTextComponent = class FormFieldTextComponent {
cdRef;
disabled$ = new BehaviorSubject(false);
hide = true;
lastTimeoutRequest;
/**
* The field's form control
*/
formControl;
/**
* Field placeholder
*/
placeholder;
/**
* if the input is a password
*/
isPassword;
/**
* Field placeholder
*/
errors;
/**
* Wheter a disable switch should be available
*/
disableSwitch = false;
/**
* Whether the field is required
*/
get required() {
return formControlIsRequired(this.formControl);
}
constructor(cdRef) {
this.cdRef = cdRef;
}
ngOnInit() {
this.disabled$.next(this.formControl.disabled);
}
/**
* Get error message
*/
getErrorMessage() {
return getControlErrorMessage(this.formControl, this.errors);
}
onDisableSwitchClick() {
this.toggleDisabled();
}
toggleDisabled() {
const disabled = !this.disabled$.value;
if (disabled === true) {
this.formControl.disable();
}
else {
this.formControl.enable();
}
this.disabled$.next(disabled);
}
togglePassword() {
this.hide = !this.hide;
this.delayedHide();
}
delayedHide(delayMS = 10000) {
if (this.isPassword && !this.hide) {
if (this.lastTimeoutRequest) {
clearTimeout(this.lastTimeoutRequest);
}
this.lastTimeoutRequest = setTimeout(() => {
this.hide = true;
this.cdRef.detectChanges();
}, delayMS);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormFieldTextComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: FormFieldTextComponent, isStandalone: true, selector: "igo-form-field-text", inputs: { formControl: "formControl", placeholder: "placeholder", isPassword: "isPassword", errors: "errors", disableSwitch: "disableSwitch" }, ngImport: i0, template: "<mat-form-field>\n <input\n matInput\n (blur)=\"delayedHide(0)\"\n [type]=\"isPassword ? (hide ? 'password' : 'text') : 'text'\"\n [required]=\"isPassword ? 'true' : required\"\n [placeholder]=\"placeholder | translate\"\n [formControl]=\"formControl\"\n (change)=\"delayedHide()\"\n />\n <mat-icon\n *ngIf=\"disableSwitch === true\"\n class=\"igo-form-disable-switch\"\n (click)=\"onDisableSwitchClick()\"\n matPrefix\n >{{\n (disabled$ | async) === true ? 'check_box_outline_blank' : 'check_box'\n }}\n </mat-icon>\n\n <button\n type=\"button\"\n *ngIf=\"isPassword\"\n matSuffix\n mat-icon-button\n (click)=\"togglePassword()\"\n >\n <mat-icon color=\"primary\">{{\n hide ? 'visibility_off' : 'visibility'\n }}</mat-icon>\n </button>\n\n <mat-error *ngIf=\"formControl.errors\">{{\n getErrorMessage() | translate\n }}</mat-error>\n</mat-form-field>\n", dependencies: [{ kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i1.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "directive", type: i1.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i5$1.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "ngmodule", type: IgoLanguageModule }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
};
FormFieldTextComponent = __decorate([
IgoFormFieldComponent('text'),
__metadata("design:paramtypes", [ChangeDetectorRef])
], FormFieldTextComponent);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormFieldTextComponent, decorators: [{
type: Component,
args: [{ selector: 'igo-form-field-text', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
MatFormFieldModule,
MatInputModule,
FormsModule,
ReactiveFormsModule,
NgIf,
MatIconModule,
MatButtonModule,
AsyncPipe,
IgoLanguageModule
], template: "<mat-form-field>\n <input\n matInput\n (blur)=\"delayedHide(0)\"\n [type]=\"isPassword ? (hide ? 'password' : 'text') : 'text'\"\n [required]=\"isPassword ? 'true' : required\"\n [placeholder]=\"placeholder | translate\"\n [formControl]=\"formControl\"\n (change)=\"delayedHide()\"\n />\n <mat-icon\n *ngIf=\"disableSwitch === true\"\n class=\"igo-form-disable-switch\"\n (click)=\"onDisableSwitchClick()\"\n matPrefix\n >{{\n (disabled$ | async) === true ? 'check_box_outline_blank' : 'check_box'\n }}\n </mat-icon>\n\n <button\n type=\"button\"\n *ngIf=\"isPassword\"\n matSuffix\n mat-icon-button\n (click)=\"togglePassword()\"\n >\n <mat-icon color=\"primary\">{{\n hide ? 'visibility_off' : 'visibility'\n }}</mat-icon>\n </button>\n\n <mat-error *ngIf=\"formControl.errors\">{{\n getErrorMessage() | translate\n }}</mat-error>\n</mat-form-field>\n" }]
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { formControl: [{
type: Input
}], placeholder: [{
type: Input
}], isPassword: [{
type: Input
}], errors: [{
type: Input
}], disableSwitch: [{
type: Input
}] } });
/**
* This component renders a textarea field
*/
let FormFieldTextareaComponent = class FormFieldTextareaComponent {
disabled$ = new BehaviorSubject(false);
/**
* The field's form control
*/
formControl;
/**
* Field placeholder
*/
placeholder;
/**
* Field placeholder
*/
errors;
/**
* Wheter a disable switch should be available
*/
disableSwitch = false;
/**
* Whether the field is required
*/
get required() {
return formControlIsRequired(this.formControl);
}
ngOnInit() {
this.disabled$.next(this.formControl.disabled);
}
/**
* Get error message
*/
getErrorMessage() {
return getControlErrorMessage(this.formControl, this.errors);
}
onDisableSwitchClick() {
this.toggleDisabled();
}
toggleDisabled() {
const disabled = !this.disabled$.value;
if (disabled === true) {
this.formControl.disable();
}
else {
this.formControl.enable();
}
this.disabled$.next(disabled);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormFieldTextareaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: FormFieldTextareaComponent, isStandalone: true, selector: "igo-form-field-textarea", inputs: { formControl: "formControl", placeholder: "placeholder", errors: "errors", disableSwitch: "disableSwitch" }, ngImport: i0, template: "<mat-form-field>\n <textarea\n matInput\n [required]=\"required\"\n [placeholder]=\"placeholder | translate\"\n [formControl]=\"formControl\"\n >\n </textarea>\n <mat-icon\n *ngIf=\"disableSwitch === true\"\n class=\"igo-form-disable-switch\"\n (click)=\"onDisableSwitchClick()\"\n matPrefix\n >{{\n (disabled$ | async) === true ? 'check_box_outline_blank' : 'check_box'\n }}\n </mat-icon>\n <mat-error *ngIf=\"formControl.errors\">{{\n getErrorMessage() | translate\n }}</mat-error>\n</mat-form-field>\n", dependencies: [{ kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i1.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "ngmodule", type: IgoLanguageModule }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
};
FormFieldTextareaComponent = __decorate([
IgoFormFieldComponent('textarea')
], FormFieldTextareaComponent);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormFieldTextareaComponent, decorators: [{
type: Component,
args: [{ selector: 'igo-form-field-textarea', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
MatFormFieldModule,
MatInputModule,
FormsModule,
ReactiveFormsModule,
NgIf,
MatIconModule,
AsyncPipe,
IgoLanguageModule
], template: "<mat-form-field>\n <textarea\n matInput\n [required]=\"required\"\n [placeholder]=\"placeholder | translate\"\n [formControl]=\"formControl\"\n >\n </textarea>\n <mat-icon\n *ngIf=\"disableSwitch === true\"\n class=\"igo-form-disable-switch\"\n (click)=\"onDisableSwitchClick()\"\n matPrefix\n >{{\n (disabled$ | async) === true ? 'check_box_outline_blank' : 'check_box'\n }}\n </mat-icon>\n <mat-error *ngIf=\"formControl.errors\">{{\n getErrorMessage() | translate\n }}</mat-error>\n</mat-form-field>\n" }]
}], propDecorators: { formControl: [{
type: Input
}], placeholder: [{
type: Input
}], errors: [{
type: Input
}], disableSwitch: [{
type: Input
}] } });
class FormService {
formBuilder;
constructor(formBuilder) {
this.formBuilder = formBuilder;
}
form(fields, groups) {
const control = this.formBuilder.group({});
fields.forEach((field) => {
control.addControl(field.name, field.control);
});
groups.forEach((group) => {
control.addControl(group.name, group.control);
});
return { fields, groups, control };
}
group(config, fields) {
const options = config.options || {};
const control = this.formBuilder.group({});
fields.forEach((field) => {
control.addControl(field.name, field.control);
});
if (options.validator) {
const validators = this.getValidators(options.validator); // convert string to actual validator
control.setValidators(validators);
}
return Object.assign({}, config, { fields, control });
}
field(config) {
const options = config.options || {};
const state = {
value: options.initialValue ?? '',
disabled: options.disabled
};
const control = this.formBuilder.control(state);
if (options.validator) {
const validators = this.getValidators(options.validator); // convert string to actual validator
control.setValidators(validators);
}
return Object.assign({ type: 'text' }, config, { control });
}
extendFieldConfig(config, partial) {
const options = Object.assign({}, config.options || {}, partial.options || {});
const inputs = Object.assign({}, config.inputs || {}, partial.inputs || {});
const subscribers = Object.assign({}, config.subscribers || {}, partial.subscribers || {});
return Object.assign({}, config, { options, inputs, subscribers });
}
getValidators(validatorOption) {
if (Array.isArray(validatorOption)) {
return validatorOption.map((validatorStr) => {
return this.getValidator(validatorStr);
});
}
return this.getValidator(validatorOption);
}
getValidator(validatorStr) {
if (typeof validatorStr !== 'string') {
return validatorStr;
}
// regex pattern to extract arguments from string for e.g applying on "minLength(8)" would extract 8
const re = /^([a-zA-Z]{3,15})\((.{0,20})\)$/;
const match = validatorStr.match(re);
if (!match) {
return Validators[validatorStr];
}
const name = match[1];
const args = match[2];
return Validators[name](args);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormService, deps: [{ token: i3.UntypedFormBuilder }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: () => [{ type: i3.UntypedFormBuilder }] });
/**
* This component renders the proper form input based on
* the field configuration it receives.
*/
class FormFieldComponent {
formFieldService;
/**
* Field configuration
*/
field;
/**
* Field inputs cache
*/
fieldInputs = undefined;
/**
* Field subscribers cache
*/
fieldSubscribers = undefined;
get fieldOptions() {
return this.field.options || {};
}
constructor(formFieldService) {
this.formFieldService = formFieldService;
}
getFieldComponent() {
return this.formFieldService.getFieldByType(this.field.type || 'text');
}
getFieldInputs() {
if (this.fieldInputs !== undefined) {
return this.fieldInputs;
}
const errors = this.fieldOptions.errors || {};
this.fieldInputs = Object.assign({
placeholder: this.field.title,
disableSwitch: this.fieldOptions.disableSwitch || false
}, Object.assign({}, this.field.inputs || {}), {
formControl: this.field.control,
errors: Object.assign({}, getDefaultErrorMessages(), errors)
});
return this.fieldInputs;
}
getFieldSubscribers() {
if (this.fieldSubscribers !== undefined) {
return this.fieldSubscribers;
}
this.fieldSubscribers = Object.assign({}, this.field.subscribers || {});
return this.fieldSubscribers;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormFieldComponent, deps: [{ token: FormFieldService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: FormFieldComponent, isStandalone: true, selector: "igo-form-field", inputs: { field: "field" }, ngImport: i0, template: "<ng-container *ngIf=\"field !== undefined\">\n <igo-dynamic-outlet\n [component]=\"getFieldComponent()\"\n [inputs]=\"getFieldInputs()\"\n [subscribers]=\"getFieldSubscribers()\"\n >\n </igo-dynamic-outlet>\n</ng-container>\n", styles: ["::ng-deep mat-form-field{width:100%}::ng-deep .igo-form-disable-switch{margin-right:8px}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: DynamicOutletComponent, selector: "igo-dynamic-outlet", inputs: ["component", "inputs", "subscribers"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormFieldComponent, decorators: [{
type: Component,
args: [{ selector: 'igo-form-field', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgIf, DynamicOutletComponent], template: "<ng-container *ngIf=\"field !== undefined\">\n <igo-dynamic-outlet\n [component]=\"getFieldComponent()\"\n [inputs]=\"getFieldInputs()\"\n [subscribers]=\"getFieldSubscribers()\"\n >\n </igo-dynamic-outlet>\n</ng-container>\n", styles: ["::ng-deep mat-form-field{width:100%}::ng-deep .igo-form-disable-switch{margin-right:8px}\n"] }]
}], ctorParameters: () => [{ type: FormFieldService }], propDecorators: { field: [{
type: Input
}] } });
const FORM_FIELD_DIRECTIVES = [
FormFieldComponent,
FormFieldSelectComponent,
FormFieldTextComponent,
FormFieldTextareaComponent
];
/**
* @deprecated import the components directly or FORM_FIELD_DIRECTIVES for every components/directives
*/
class IgoFormFieldModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: IgoFormFieldModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.15", ngImport: i0, type: IgoFormFieldModule, imports: [FormFieldComponent, FormFieldSelectComponent, FormFieldTextComponent, FormFieldTextareaComponent], exports: [FormFieldComponent, FormFieldSelectComponent, FormFieldTextComponent, FormFieldTextareaComponent] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: IgoFormFieldModule, imports: [FORM_FIELD_DIRECTIVES] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: IgoFormFieldModule, decorators: [{
type: NgModule,
args: [{
imports: [...FORM_FIELD_DIRECTIVES],
exports: [...FORM_FIELD_DIRECTIVES]
}]
}] });
/**
* A configurable form, optionnally bound to an entity
* (for example in case of un update). Submitting that form
* emits an event with the form data but no other operation is performed.
*/
class FormGroupComponent {
/**
* Form field group
*/
group;
/**
* Field placeholder
*/
errors;
/**
* Form group control
*/
get formControl() {
return this.group.control;
}
/**
* Return the number of columns a field should occupy.
* The maximum allowed is 2, even if the field config says more.
* @param field Field
* @returns Number of columns
* @internal
*/
getFieldColSpan(field) {
let colSpan = 2;
const options = field.options || {};
if (options.cols && options.cols > 0) {
colSpan = Math.min(options.cols, 2);
}
return colSpan;
}
/**
* Return the number of columns a field should occupy.
* The maximum allowed is 2, even if the field config says more.
* @param field Field
* @returns Number of columns
* @internal
*/
getFieldNgClass(field) {
const colspan = this.getFieldColSpan(field);
return { [`igo-form-field-colspan-${colspan}`]: true };
}
/**
* Get error message
*/
getErrorMessage() {
const options = this.group.options || {};
return getControlErrorMessage(this.formControl, options.errors || {});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: FormGroupComponent, isStandalone: true, selector: "igo-form-group", inputs: { group: "group", errors: "errors" }, ngImport: i0, template: "<div *ngIf=\"group && group.fields.length > 0\" class=\"igo-form-group-fields\">\n <div\n *ngFor=\"let field of group.fields\"\n class=\"igo-form-field-wrapper\"\n [ngClass]=\"getFieldNgClass(field)\"\n >\n <igo-form-field [field]=\"field\"></igo-form-field>\n </div>\n</div>\n\n<div class=\"igo-form-group-extra-content\">\n <ng-content></ng-content>\n</div>\n\n<mat-error *ngIf=\"formControl.errors\">{{\n getErrorMessage() | translate\n}}</mat-error>\n", styles: [":host{width:100%;height:100%;display:block;overflow:auto;padding:10px 5px;box-sizing:border-box}:host .igo-form-field-colspan-2{width:100%}:host .igo-form-field-colspan-1{width:50%}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: FormFieldComponent, selector: "igo-form-field", inputs: ["field"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "directive", type: i1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: IgoLanguageModule }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormGroupComponent, decorators: [{
type: Component,
args: [{ selector: 'igo-form-group', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
NgIf,
NgFor,
NgClass,
FormFieldComponent,
MatFormFieldModule,
IgoLanguageModule
], template: "<div *ngIf=\"group && group.fields.length > 0\" class=\"igo-form-group-fields\">\n <div\n *ngFor=\"let field of group.fields\"\n class=\"igo-form-field-wrapper\"\n [ngClass]=\"getFieldNgClass(field)\"\n >\n <igo-form-field [field]=\"field\"></igo-form-field>\n </div>\n</div>\n\n<div class=\"igo-form-group-extra-content\">\n <ng-content></ng-content>\n</div>\n\n<mat-error *ngIf=\"formControl.errors\">{{\n getErrorMessage() | translate\n}}</mat-error>\n", styles: [":host{width:100%;height:100%;display:block;overflow:auto;padding:10px 5px;box-sizing:border-box}:host .igo-form-field-colspan-2{width:100%}:host .igo-form-field-colspan-1{width:50%}\n"] }]
}], propDecorators: { group: [{
type: Input
}], errors: [{
type: Input
}] } });
/**
* @deprecated import the FormGroupComponent directly
*/
class IgoFormGroupModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: IgoFormGroupModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.15", ngImport: i0, type: IgoFormGroupModule, imports: [FormGroupComponent], exports: [FormGroupComponent] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: IgoFormGroupModule, imports: [FormGroupComponent] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: IgoFormGroupModule, decorators: [{
type: NgModule,
args: [{
imports: [FormGroupComponent],
exports: [FormGroupComponent]
}]
}] });
const FORM_DIRECTIVES = [
...FORM_FIELD_DIRECTIVES,
FormGroupComponent,
FormComponent
];
/**
* @deprecated import the components directly or FORM_DIRECTIVES for every components/directives
*/
class IgoFormModule {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: IgoFormModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.15", ngImport: i0, type: IgoFormModule, imports: [FormFieldComponent, FormFieldSelectComponent, FormFieldTextComponent, FormFieldTextareaComponent, FormGroupComponent,
FormComponent], exports: [FormFieldComponent, FormFieldSelectComponent, FormFieldTextComponent, FormFieldTextareaComponent, FormGroupComponent,
FormComponent] });
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: IgoFormModule, imports: [FORM_DIRECTIVES] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: IgoFormModule, decorators: [{
type: NgModule,
args: [{
imports: [...FORM_DIRECTIVES],
exports: [...FORM_DIRECTIVES]
}]
}] });
class FormDialogComponent {
languageService;
dialogRef;
formService;
data;
form$ = new BehaviorSubject(undefined);
data$ = new BehaviorSubject(undefined);
constructor(languageService, dialogRef, formService, data) {
this.languageService = languageService;
this.dialogRef = dialogRef;
this.formService = formService;
this.data = data;
this.data.processButtonText =
this.data.processButtonText ?? 'igo.common.formDialog.processButtonText';
this.data.cancelButtonText =
this.data.cancelButtonText ?? 'igo.common.formDialog.cancelButtonText';
this.data.title = this.data.title ?? 'igo.common.formDialog.title';
this.data$ = this.data.data$;
const fields = [];
const groups = [];
this.data.formFieldConfigs?.map((config) => fields.push(this.formService.field(config)));
this.data.formGroupsConfigs?.map((formGroupsConfig) => {
const fields = formGroupsConfig.formFieldConfigs?.map((config) => this.formService.field(config));
groups.push(this.formService.group({ name: formGroupsConfig.name }, fields));
});
const form = this.formService.form(fields, groups);
this.form$.next(form);
}
onSubmit(data) {
const form = this.form$.getValue();
if (form.control.valid) {
this.dialogRef.close(data);
}
else {
if (form.groups?.length) {
form.groups.map((group) => {
Object.keys(group.control.controls).map((k) => {
group.control.controls[k].markAsTouched();
group.control.controls[k].updateValueAndValidity();
});
});
}
else {
form.fields.map((f) => {
f.control.markAsTouched();
f.control.updateValueAndValidity();
});
}
}
}
cancel() {
this.dialogRef.close();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FormDialogComponent, deps: [{ token: i1$1.LanguageService }, { token: i2$2.MatDialogRef }, { token: FormService }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: FormDialogComponent, isStandalone: true, selector: "igo-form-dialog", ngImport: i0, template: "<h1 mat-dialog-title>{{ data.title | translate }}</h1>\n\n<igo-form\n *ngIf=\"form$ | async as form\"\n [form]=\"form\"\n [formData]=\"data$ | async\"\n (submitForm)=\"onSubmit($event)\"\n>\n <div *ngIf=\"form.fields.length\" class=\"form-dialog-container\">\n <igo-form-field\n *ngFor=\"let field of form.fields\"\n [field]=\"field\"\n ></igo-form-field>\n <igo-form-group\n *ngFor=\"let group of form.groups\"\n [group]=\"group\"\n ></igo-form-group>\n </div>\n\n <div formButtons mat-dialog-actions>\n <button mat-stroked-button type=\"button\" color=\"primary\" (click)=\"cancel()\">\n {{ data.cancelButtonText | translate }}\n </button>\n <button mat-flat-button type=\"submit\" color=\"primary\">\n {{ data.processButtonText | translate }}\n </button>\n </div>\n</igo-form>\n<div>\n <igo-custom-html\n *ngIf=\"data.notice && data.notice !== ''\"\n [html]=\"data.notice\"\n >\n </igo-custom-html>\n</div>\n", styles: [":host div[mat-dialog-actions]{margin:10px 0 0}:host .form-dialog-container{width:100%;padding:10px}:host .form-dialog-container igo-form-field,:host .form-dialog-container igo-form-group{display:block;height:auto}\n"], dependencies: [{ kind: "directive", type: MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: FormComponent, selector: "igo-form", inputs: ["form", "formData", "autocomplete"], outputs: ["submitForm"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", t