src/app/features/public-form/edit-prefilled-values/edit-prefilled-values.component.ts
CustomFormControlDirective<Record<string, DefaultValueConfig>>
| changeDetection | ChangeDetectionStrategy.OnPush |
| providers |
EditPrefilledValuesComponent
|
| selector | app-edit-prefilled-values |
| standalone | true |
| imports |
MatFormFieldModule
MatSelectModule
MatTooltipModule
FontAwesomeModule
MatButtonModule
|
| styleUrls | ./edit-prefilled-values.component.scss |
| templateUrl | ./edit-prefilled-values.component.html |
No results matching.
AdminDefaultValueComponent
ReactiveFormsModule
MatFormFieldModule
MatSelectModule
MatTooltipModule
HelpButtonComponent
FontAwesomeModule
MatButtonModule
EntityFieldSelectComponent
CustomFormControlDirective<Record<string, DefaultValueConfig>>
OnInit
EditComponent
Properties |
|
Methods |
Inputs |
Outputs |
Accessors |
| entity | |
Type : Entity
|
|
| formFieldConfig | |
Type : FormFieldConfig
|
|
| aria-describedby | |
Type : string
|
|
|
Inherited from
CustomFormControlDirective
|
|
| disabled | |
Type : boolean
|
|
|
Inherited from
CustomFormControlDirective
|
|
| ngControl | |
Type : any
|
|
Default value : inject(NgControl, { optional: true, self: true })
|
|
|
Inherited from
CustomFormControlDirective
|
|
| placeholder | |
Type : string
|
|
|
Inherited from
CustomFormControlDirective
|
|
| required | |
Type : boolean
|
|
|
Inherited from
CustomFormControlDirective
|
|
| value | |
Type : T
|
|
|
Inherited from
CustomFormControlDirective
|
|
| valueChange | |
Type : EventEmitter
|
|
|
Inherited from
CustomFormControlDirective
|
|
| addPrefilledFields |
addPrefilledFields()
|
|
Returns :
void
|
| getSchemaField | ||||||
getSchemaField(fieldId: string)
|
||||||
|
Parameters :
Returns :
EntitySchemaField
|
| removePrefilledFields | ||||||
removePrefilledFields(index: number)
|
||||||
|
Parameters :
Returns :
void
|
| blur |
blur()
|
|
Inherited from
CustomFormControlDirective
|
|
Returns :
void
|
| focus |
focus()
|
|
Inherited from
CustomFormControlDirective
|
|
Returns :
void
|
| onContainerClick | ||||||
onContainerClick(event: MouseEvent)
|
||||||
|
Inherited from
CustomFormControlDirective
|
||||||
|
Parameters :
Returns :
void
|
| registerOnChange | ||||||
registerOnChange(fn: any)
|
||||||
|
Inherited from
CustomFormControlDirective
|
||||||
|
Parameters :
Returns :
void
|
| registerOnTouched | ||||||
registerOnTouched(fn: any)
|
||||||
|
Inherited from
CustomFormControlDirective
|
||||||
|
Parameters :
Returns :
void
|
| setDescribedByIds | ||||||
setDescribedByIds(ids: string[])
|
||||||
|
Inherited from
CustomFormControlDirective
|
||||||
|
Parameters :
Returns :
void
|
| setDisabledState | ||||||
setDisabledState(isDisabled: boolean)
|
||||||
|
Inherited from
CustomFormControlDirective
|
||||||
|
Parameters :
Returns :
void
|
| writeValue | |||||||||||||||
writeValue(value: T, notifyFormControl: unknown)
|
|||||||||||||||
|
Inherited from
CustomFormControlDirective
|
|||||||||||||||
|
Implementation for Angular ControlValueAccessor interface that links the form control value to the component value
Parameters :
Returns :
void
|
| Optional entityConstructor |
Type : EntityConstructor
|
|
not set for configs in the multi form format, which hold no top-level entity type |
| entitySchemaField |
Type : EntitySchemaField
|
| Readonly isDisabled |
Type : unknown
|
Default value : signal(false)
|
| prefilledValueSettings |
Type : unknown
|
Default value : this.fb.group({
prefilledValue: this.fb.array([]),
})
|
| controlType |
Type : string
|
Default value : "custom-control"
|
|
Inherited from
CustomFormControlDirective
|
| elementRef |
Type : unknown
|
Default value : inject<ElementRef<HTMLElement>>(ElementRef)
|
|
Inherited from
CustomFormControlDirective
|
| Readonly enabled |
Type : Signal<boolean>
|
Default value : computed(() => !this._disabled())
|
|
Inherited from
CustomFormControlDirective
|
|
Whether the control is currently enabled, as a signal (tracks disabled). |
| errorStateMatcher |
Type : unknown
|
Default value : inject(ErrorStateMatcher)
|
|
Inherited from
CustomFormControlDirective
|
| id |
Type : unknown
|
Default value : `custom-form-control-${CustomFormControlDirective.nextId++}`
|
|
Inherited from
CustomFormControlDirective
|
| Static nextId |
Type : number
|
Default value : 0
|
|
Inherited from
CustomFormControlDirective
|
| onChange |
Type : unknown
|
Default value : () => {...}
|
|
Inherited from
CustomFormControlDirective
|
| onTouched |
Type : unknown
|
Default value : () => {...}
|
|
Inherited from
CustomFormControlDirective
|
| parentForm |
Type : unknown
|
Default value : inject(NgForm, { optional: true })
|
|
Inherited from
CustomFormControlDirective
|
| parentFormGroup |
Type : unknown
|
Default value : inject(FormGroupDirective, { optional: true })
|
|
Inherited from
CustomFormControlDirective
|
| stateChanges |
Type : unknown
|
Default value : new Subject<void>()
|
|
Inherited from
CustomFormControlDirective
|
| Readonly valueSignal |
Type : Signal<T>
|
Default value : computed(() => this._value())
|
|
Inherited from
CustomFormControlDirective
|
|
The current value of the control as a signal.
Authoritative in both modes: it reflects the bound |
| prefilledValues |
getprefilledValues()
|
import { EditComponent } from "#src/app/core/entity/entity-field-edit/dynamic-edit/edit-component.interface";
import {
ChangeDetectionStrategy,
Component,
inject,
input,
OnInit,
signal,
} from "@angular/core";
import {
AbstractControl,
FormArray,
FormBuilder,
ReactiveFormsModule,
ValidatorFn,
ValidationErrors,
Validators,
} from "@angular/forms";
import { MatButtonModule } from "@angular/material/button";
import {
MatFormFieldControl,
MatFormFieldModule,
} from "@angular/material/form-field";
import { MatSelectModule } from "@angular/material/select";
import { MatTooltipModule } from "@angular/material/tooltip";
import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";
import { CustomFormControlDirective } from "app/core/common-components/basic-autocomplete/custom-form-control.directive";
import { FormFieldConfig } from "app/core/common-components/entity-form/FormConfig";
import { HelpButtonComponent } from "app/core/common-components/help-button/help-button.component";
import { DynamicComponent } from "app/core/config/dynamic-components/dynamic-component.decorator";
import { EntityRegistry } from "app/core/entity/database-entity.decorator";
import { EntityFieldSelectComponent } from "app/core/entity/entity-field-select/entity-field-select.component";
import { Entity, EntityConstructor } from "app/core/entity/model/entity";
import { EntitySchemaField } from "app/core/entity/schema/entity-schema-field";
import { AdminDefaultValueComponent } from "../../../core/default-values/admin-default-value/admin-default-value.component";
import { DefaultValueConfig } from "../../../core/default-values/default-value-config";
const defaultValueCompleteValidator: ValidatorFn = (
control: AbstractControl,
): ValidationErrors | null => {
const val: DefaultValueConfig = control.value;
if (!val) {
return { incompleteDefaultValue: true };
}
if (val.mode && !val.config) {
return { incompleteDefaultValue: true };
}
if (
val.config &&
typeof val.config === "object" &&
"value" in val.config &&
(val.config as { value: unknown }).value == null
) {
return { incompleteDefaultValue: true };
}
return null;
};
@DynamicComponent("EditPrefilledValuesComponent")
@Component({
selector: "app-edit-prefilled-values",
standalone: true,
imports: [
AdminDefaultValueComponent,
ReactiveFormsModule,
MatFormFieldModule,
MatSelectModule,
MatTooltipModule,
HelpButtonComponent,
FontAwesomeModule,
MatButtonModule,
EntityFieldSelectComponent,
],
templateUrl: "./edit-prefilled-values.component.html",
styleUrls: ["./edit-prefilled-values.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{ provide: MatFormFieldControl, useExisting: EditPrefilledValuesComponent },
],
})
export class EditPrefilledValuesComponent
extends CustomFormControlDirective<Record<string, DefaultValueConfig>>
implements OnInit, EditComponent
{
formFieldConfig = input<FormFieldConfig>();
entity = input<Entity>();
/** not set for configs in the multi form format, which hold no top-level entity type */
entityConstructor?: EntityConstructor;
entitySchemaField: EntitySchemaField;
private readonly entities = inject(EntityRegistry);
private readonly fb = inject(FormBuilder);
readonly isDisabled = signal(false);
prefilledValueSettings = this.fb.group({
prefilledValue: this.fb.array([]),
});
ngOnInit(): void {
const entity = this.entity();
if (!entity) return;
// configs in the multi form format do not hold a top-level entity type
this.entityConstructor = entity["entity"]
? this.entities.get(entity["entity"])
: undefined;
this.initializePrefilledValues();
this.prefilledValueSettings.valueChanges.subscribe((value) =>
this.updateFieldGroups(value as { prefilledValue: PrefilledValue[] }),
);
this.formControl.statusChanges.subscribe(() => {
const disabled = this.formControl.disabled;
this.isDisabled.set(disabled);
if (disabled) {
this.prefilledValueSettings.disable({ emitEvent: false });
} else {
this.prefilledValueSettings.enable({ emitEvent: false });
}
});
if (this.formControl.disabled) {
this.isDisabled.set(true);
this.prefilledValueSettings.disable({ emitEvent: false });
}
}
get prefilledValues(): FormArray {
return this.prefilledValueSettings.get("prefilledValue") as FormArray;
}
private initializePrefilledValues(): void {
let fields = this.formControl.value;
if (fields && typeof fields === "object" && !Array.isArray(fields)) {
for (const [fieldId, defVal] of Object.entries(
fields as Record<string, DefaultValueConfig>,
)) {
this.prefilledValues.push(
this.fb.group({
field: [fieldId, Validators.required],
defaultValue: [defVal, defaultValueCompleteValidator],
}),
);
}
return;
}
}
addPrefilledFields(): void {
this.prefilledValues.push(
this.fb.group({
field: ["", Validators.required],
defaultValue: [{ mode: "static" }, defaultValueCompleteValidator],
}),
);
}
removePrefilledFields(index: number): void {
if (index < 0 || index >= this.prefilledValues.length) {
return;
}
this.prefilledValues.removeAt(index);
this.formControl.markAsDirty();
}
getSchemaField(fieldId: string): EntitySchemaField {
return this.entityConstructor?.schema.get(fieldId);
}
private updateFieldGroups(value: { prefilledValue: PrefilledValue[] }): void {
if (!value?.prefilledValue) return;
if (this.prefilledValueSettings.invalid) {
this.formControl.setErrors({ invalid: true });
this.prefilledValueSettings.markAllAsTouched();
return;
}
const updatedFields: Record<string, DefaultValueConfig> = {};
value.prefilledValue.forEach(({ field, defaultValue }) => {
if (field && defaultValue != null) updatedFields[field] = defaultValue;
});
const hasChanged =
JSON.stringify(updatedFields) !==
JSON.stringify(this.formControl.value ?? {});
this.formControl.setValue(updatedFields);
if (hasChanged) {
this.formControl.markAsDirty();
}
}
}
interface PrefilledValue {
field: string;
defaultValue: DefaultValueConfig;
hideFromForm?: boolean;
}
<div
class="defaultvalue-container padding-regular margin-bottom-small"
[class.disabled]="isDisabled()"
>
<!-- without an entity type there are no fields to pick a value for -->
@if (entityConstructor) {
<form [formGroup]="prefilledValueSettings">
<div formArrayName="prefilledValue">
@for (
fieldGroup of prefilledValues.controls;
track $index;
let i = $index
) {
<div
[formGroupName]="i"
class="flex-row flex-wrap align-center gap-regular padding-regular margin-top-regular mat-elevation-z2 container"
>
<div class="flex-row align-center">
<mat-form-field class="full-width-field" floatLabel="always">
<mat-label i18n>Field</mat-label>
<app-entity-field-select
[entityType]="entityConstructor"
formControlName="field"
/>
</mat-form-field>
<app-help-button
text="Select a field for which you want to set a default value."
i18n-text
></app-help-button>
</div>
@if (fieldGroup.get("field").value) {
<div class="flex-grow">
<div class="full-width-field">
<app-admin-default-value
formControlName="defaultValue"
[entityType]="entityConstructor"
[entitySchemaField]="
getSchemaField(fieldGroup.get('field').value)
"
></app-admin-default-value>
</div>
</div>
}
<button
mat-icon-button
[disabled]="isDisabled()"
(click)="removePrefilledFields(i)"
matTooltip="Remove default value"
i18n-matTooltip
>
<fa-icon icon="trash"></fa-icon>
</button>
</div>
}
</div>
</form>
<div class="add-new-defaultvalue-field">
<button
mat-stroked-button
class="add-new-defaultvalue-button"
color="accent"
(click)="addPrefilledFields()"
[disabled]="isDisabled() || prefilledValues.invalid"
matTooltip="Add a fixed value for another field"
i18n-matTooltip
>
<fa-icon
aria-hidden="true"
icon="plus-circle"
class="standard-icon-with-text"
></fa-icon>
<span i18n>Add pre-filled value</span>
</button>
</div>
}
</div>
./edit-prefilled-values.component.scss
@use "variables/colors";
@use "variables/sizes";
.defaultvalue-container {
overflow: hidden;
&.disabled {
opacity: 0.5;
pointer-events: none;
}
}
.container {
border-radius: sizes.$regular;
}
.add-new-defaultvalue-field {
display: flex;
justify-content: center;
margin-top: 30px;
}
.add-new-defaultvalue-button {
width: 50%;
border-radius: 20px;
padding: 22px;
background-color: aliceblue;
}