From 17333d094175b1be20bd30a8cee7a73d679b8191 Mon Sep 17 00:00:00 2001 From: Julien Schneider Date: Fri, 1 Mar 2024 14:53:28 +0100 Subject: [PATCH] refactor: forms using multi language inputs should be typed (#1494) --- .../create-project-form-page.component.ts | 16 ++--- .../edit-project-form-page.component.ts | 34 +++++----- .../list-item-element.component.ts | 28 ++------ .../create-list-item-dialog.component.ts | 12 ++-- .../edit-list-item-dialog.component.ts | 17 ++--- .../list-item-form.component.ts | 42 +++--------- .../list-item-form/list-item-form.type.ts | 7 ++ .../reusable-list-item-form.component.ts | 66 +++++------------- .../create-list-info-page.component.ts | 11 +-- .../edit-list-info-dialog.component.ts | 14 ++-- .../list-info-form.type.ts | 7 ++ .../reusable-list-info-form.component.ts | 64 +++++------------- .../create-resource-class-dialog.component.ts | 12 ++-- .../edit-resource-class-dialog.component.ts | 17 +++-- .../project/ontology/ontology.component.html | 2 +- .../project/ontology/ontology.component.ts | 7 +- .../resource-class-form.component.ts | 67 ++++++------------- .../resource-class-form.type.ts | 8 +++ .../project-form.type.ts | 10 +++ .../reusable-project-form.component.ts | 55 ++++++--------- .../shared/app-string-literal/src/index.ts | 1 + .../src/lib/default-multi-language-form.ts | 20 ++++++ 22 files changed, 218 insertions(+), 299 deletions(-) create mode 100644 apps/dsp-app/src/app/project/list/list-item-form/list-item-form.type.ts create mode 100644 apps/dsp-app/src/app/project/list/reusable-list-info-form/list-info-form.type.ts create mode 100644 apps/dsp-app/src/app/project/ontology/resource-class-form/resource-class-form.type.ts create mode 100644 apps/dsp-app/src/app/project/reusable-project-form/project-form.type.ts create mode 100644 libs/vre/shared/app-string-literal/src/lib/default-multi-language-form.ts diff --git a/apps/dsp-app/src/app/project/create-project-form-page/create-project-form-page.component.ts b/apps/dsp-app/src/app/project/create-project-form-page/create-project-form-page.component.ts index facd2a2961..4be4cefb2b 100644 --- a/apps/dsp-app/src/app/project/create-project-form-page/create-project-form-page.component.ts +++ b/apps/dsp-app/src/app/project/create-project-form-page/create-project-form-page.component.ts @@ -1,6 +1,5 @@ import { Location } from '@angular/common'; import { Component } from '@angular/core'; -import { FormGroup } from '@angular/forms'; import { Router } from '@angular/router'; import { ProjectApiService } from '@dasch-swiss/vre/shared/app-api'; import { RouteConstants } from '@dasch-swiss/vre/shared/app-config'; @@ -8,6 +7,7 @@ import { ProjectService } from '@dasch-swiss/vre/shared/app-helper-services'; import { LoadProjectsAction } from '@dasch-swiss/vre/shared/app-state'; import { Store } from '@ngxs/store'; import { finalize } from 'rxjs/operators'; +import { ProjectForm } from '../reusable-project-form/project-form.type'; @Component({ selector: 'app-create-project-form-page', @@ -21,7 +21,7 @@ import { finalize } from 'rxjs/operators'; description: [], keywords: [] }" - (formValueChange)="form = $event"> + (afterFormInit)="form = $event">
@@ -37,7 +35,7 @@ export class EditListInfoDialogProps { `, }) export class EditListInfoDialogComponent { - form: FormGroup; + form: ListInfoForm; loading = false; formData = { labels: this.data.list.labels as MultiLanguages, comments: this.data.list.comments as MultiLanguages }; @@ -54,8 +52,8 @@ export class EditListInfoDialogComponent { const listInfoUpdateData: UpdateListInfoRequest = new UpdateListInfoRequest(); listInfoUpdateData.projectIri = this.data.projectIri; listInfoUpdateData.listIri = this.data.list.id; - listInfoUpdateData.labels = this.form.value.labels; - listInfoUpdateData.comments = this.form.value.comments; + listInfoUpdateData.labels = this.form.value.labels as StringLiteral[]; + listInfoUpdateData.comments = this.form.value.comments as StringLiteral[]; this._listApiService.updateInfo(listInfoUpdateData.listIri, listInfoUpdateData).subscribe(response => { this._store.dispatch(new LoadListsInProjectAction(this.data.projectIri)); diff --git a/apps/dsp-app/src/app/project/list/reusable-list-info-form/list-info-form.type.ts b/apps/dsp-app/src/app/project/list/reusable-list-info-form/list-info-form.type.ts new file mode 100644 index 0000000000..f4029dc624 --- /dev/null +++ b/apps/dsp-app/src/app/project/list/reusable-list-info-form/list-info-form.type.ts @@ -0,0 +1,7 @@ +import { FormGroup } from '@angular/forms'; +import { MultiLanguageFormArray } from '@dasch-swiss/vre/shared/app-string-literal'; + +export type ListInfoForm = FormGroup<{ + labels: MultiLanguageFormArray; + comments: MultiLanguageFormArray; +}>; diff --git a/apps/dsp-app/src/app/project/list/reusable-list-info-form/reusable-list-info-form.component.ts b/apps/dsp-app/src/app/project/list/reusable-list-info-form/reusable-list-info-form.component.ts index 751814709f..75af867528 100644 --- a/apps/dsp-app/src/app/project/list/reusable-list-info-form/reusable-list-info-form.component.ts +++ b/apps/dsp-app/src/app/project/list/reusable-list-info-form/reusable-list-info-form.component.ts @@ -1,80 +1,52 @@ -import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { MultiLanguageFormArray, MultiLanguages } from '@dasch-swiss/vre/shared/app-string-literal'; -import { Subscription } from 'rxjs'; -import { startWith } from 'rxjs/operators'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { FormBuilder, Validators } from '@angular/forms'; +import { DEFAULT_MULTILANGUAGE_FORM, MultiLanguages } from '@dasch-swiss/vre/shared/app-string-literal'; import { atLeastOneStringRequired } from '../../../main/form-validators/at-least-one-string-required.validator'; +import { ListInfoForm } from './list-info-form.type'; @Component({ selector: 'app-reusable-list-info-form', template: ` `, }) -export class ReusableListInfoFormComponent implements OnInit, OnDestroy { +export class ReusableListInfoFormComponent implements OnInit { @Input() formData: { labels: MultiLanguages; comments: MultiLanguages; }; + @Output() afterFormInit = new EventEmitter(); - @Output() formValueChange = new EventEmitter(); - - form: FormGroup; - subscription: Subscription; - - // TODO remove with typed forms - get labelsControl() { - return this.form.get('labels') as MultiLanguageFormArray; - } - - // TODO remove with typed forms - get commentsControl() { - return this.form.get('comments') as MultiLanguageFormArray; - } + form: ListInfoForm; constructor(private _fb: FormBuilder) {} ngOnInit() { this._buildForm(); - - this.subscription = this.form.valueChanges.pipe(startWith(null)).subscribe(z => { - this.formValueChange.emit(this.form); - }); - } - - ngOnDestroy() { - this.subscription.unsubscribe(); + this.afterFormInit.emit(this.form); } _buildForm() { this.form = this._fb.group({ - labels: this._fb.array( - this.formData.labels.map(({ language, value }) => - this._fb.group({ - language, - value: [value, [Validators.maxLength(2000)]], - }) - ), - atLeastOneStringRequired('value') + labels: DEFAULT_MULTILANGUAGE_FORM( + this.formData.labels, + [Validators.maxLength(2000)], + [atLeastOneStringRequired('value')] ), - comments: this._fb.array( - this.formData.comments.map(({ language, value }) => - this._fb.group({ - language, - value: [value, [Validators.maxLength(2000)]], - }) - ), - atLeastOneStringRequired('value') + comments: DEFAULT_MULTILANGUAGE_FORM( + this.formData.comments, + [Validators.maxLength(2000)], + [atLeastOneStringRequired('value')] ), }); } diff --git a/apps/dsp-app/src/app/project/ontology/create-resource-class-dialog/create-resource-class-dialog.component.ts b/apps/dsp-app/src/app/project/ontology/create-resource-class-dialog/create-resource-class-dialog.component.ts index 604c5dc203..9532c9055f 100644 --- a/apps/dsp-app/src/app/project/ontology/create-resource-class-dialog/create-resource-class-dialog.component.ts +++ b/apps/dsp-app/src/app/project/ontology/create-resource-class-dialog/create-resource-class-dialog.component.ts @@ -1,9 +1,9 @@ import { Component, Inject, OnInit } from '@angular/core'; -import { FormGroup } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { CreateResourceClass, KnoraApiConnection, UpdateOntology } from '@dasch-swiss/dsp-js'; +import { CreateResourceClass, KnoraApiConnection, StringLiteral, UpdateOntology } from '@dasch-swiss/dsp-js'; import { DspApiConnectionToken } from '@dasch-swiss/vre/shared/app-config'; import { tap } from 'rxjs/operators'; +import { ResourceClassForm } from '../resource-class-form/resource-class-form.type'; export interface CreateResourceClassDialogProps { id: string; @@ -19,7 +19,7 @@ export interface CreateResourceClassDialogProps {
+ (afterFormInit)="form = $event">
@@ -38,7 +38,7 @@ export interface CreateResourceClassDialogProps { }) export class CreateResourceClassDialogComponent implements OnInit { loading = false; - form: FormGroup; + form: ResourceClassForm; constructor( @Inject(DspApiConnectionToken) @@ -84,8 +84,8 @@ export class CreateResourceClassDialogComponent implements OnInit { const newResClass = new CreateResourceClass(); newResClass.name = this.form.value.name; - newResClass.label = this.form.value.labels; - newResClass.comment = this.form.value.comments; + newResClass.label = this.form.value.labels as StringLiteral[]; + newResClass.comment = this.form.value.comments as StringLiteral[]; newResClass.subClassOf = [this.data.id]; onto.entity = newResClass; diff --git a/apps/dsp-app/src/app/project/ontology/edit-resource-class-dialog/edit-resource-class-dialog.component.ts b/apps/dsp-app/src/app/project/ontology/edit-resource-class-dialog/edit-resource-class-dialog.component.ts index 3280559dee..622dbcbda6 100644 --- a/apps/dsp-app/src/app/project/ontology/edit-resource-class-dialog/edit-resource-class-dialog.component.ts +++ b/apps/dsp-app/src/app/project/ontology/edit-resource-class-dialog/edit-resource-class-dialog.component.ts @@ -1,22 +1,27 @@ import { Component, Inject, OnInit } from '@angular/core'; -import { FormGroup } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { DeleteResourceClassComment, KnoraApiConnection, ResourceClassDefinitionWithAllLanguages, + StringLiteral, UpdateOntology, UpdateResourceClassComment, UpdateResourceClassLabel, } from '@dasch-swiss/dsp-js'; import { DspApiConnectionToken } from '@dasch-swiss/vre/shared/app-config'; +import { MultiLanguages } from '@dasch-swiss/vre/shared/app-string-literal'; import { switchMap, tap } from 'rxjs/operators'; +import { ResourceClassForm } from '../resource-class-form/resource-class-form.type'; export interface EditResourceClassDialogProps { id: string; title: string; ontologyId: string; lastModificationDate: string; + name: string; + labels: MultiLanguages; + comments: MultiLanguages; } @Component({ @@ -25,8 +30,8 @@ export interface EditResourceClassDialogProps {
+ [formData]="{ name: data.name, labels: data.labels, comments: data.comments }" + (afterFormInit)="form = $event">
@@ -45,7 +50,7 @@ export interface EditResourceClassDialogProps { }) export class EditResourceClassDialogComponent implements OnInit { loading = false; - form: FormGroup; + form: ResourceClassForm; lastModificationDate: string; constructor( @@ -71,7 +76,7 @@ export class EditResourceClassDialogComponent implements OnInit { const updateLabel = new UpdateResourceClassLabel(); updateLabel.id = this.data.id; - updateLabel.labels = this.form.value.labels; + updateLabel.labels = this.form.value.labels as StringLiteral[]; onto4Label.entity = updateLabel; // comment @@ -80,7 +85,7 @@ export class EditResourceClassDialogComponent implements OnInit { const updateComment = new UpdateResourceClassComment(); updateComment.id = this.data.id; - updateComment.comments = this.form.value.comments; + updateComment.comments = this.form.value.comments as StringLiteral[]; onto4Comment.entity = updateComment; this._dspApiConnection.v2.onto diff --git a/apps/dsp-app/src/app/project/ontology/ontology.component.html b/apps/dsp-app/src/app/project/ontology/ontology.component.html index 496d4cb3d7..677b1052d0 100644 --- a/apps/dsp-app/src/app/project/ontology/ontology.component.html +++ b/apps/dsp-app/src/app/project/ontology/ontology.component.html @@ -158,7 +158,7 @@ [projectStatus]="(project$ | async)?.status" [expanded]="expandClasses" [userCanEdit]="isAdmin$ | async" - (editResourceClass)="updateResourceClass($event)" + (editResourceClass)="updateResourceClass($event, resClass)" (deleteResourceClass)="deleteResourceClass($event.iri)" (updatePropertyAssignment)="initOntologiesList()" [updatePropertyAssignment$]="updatePropertyAssignment$"> diff --git a/apps/dsp-app/src/app/project/ontology/ontology.component.ts b/apps/dsp-app/src/app/project/ontology/ontology.component.ts index 86eb039101..440cc2a347 100644 --- a/apps/dsp-app/src/app/project/ontology/ontology.component.ts +++ b/apps/dsp-app/src/app/project/ontology/ontology.component.ts @@ -19,6 +19,7 @@ import { ReadOntology, ReadProject, ReadUser, + ResourceClassDefinitionWithAllLanguages, } from '@dasch-swiss/dsp-js'; import { getAllEntityDefinitionsAsArray } from '@dasch-swiss/vre/shared/app-api'; import { DspApiConnectionToken, RouteConstants } from '@dasch-swiss/vre/shared/app-config'; @@ -46,6 +47,7 @@ import { SetCurrentProjectOntologyPropertiesAction, UserSelectors, } from '@dasch-swiss/vre/shared/app-state'; +import { MultiLanguages } from '@dasch-swiss/vre/shared/app-string-literal'; import { Actions, Select, Store, ofActionSuccessful } from '@ngxs/store'; import { Observable, Subject, combineLatest } from 'rxjs'; import { map, switchMap, take, takeUntil } from 'rxjs/operators'; @@ -438,7 +440,7 @@ export class OntologyComponent extends ProjectBase implements OnInit, OnDestroy }); } - updateResourceClass(resClassInfo: DefaultClass): void { + updateResourceClass(resClassInfo: DefaultClass, resClass: ResourceClassDefinitionWithAllLanguages): void { const currentOntology = this._store.selectSnapshot(OntologiesSelectors.currentOntology); this._dialog @@ -448,6 +450,9 @@ export class OntologyComponent extends ProjectBase implements OnInit, OnDestroy title: resClassInfo.label, ontologyId: currentOntology.id, lastModificationDate: currentOntology.lastModificationDate, + name: resClass.label, + comments: resClass.comments as MultiLanguages, + labels: resClass.labels as MultiLanguages, }, }) .afterClosed() diff --git a/apps/dsp-app/src/app/project/ontology/resource-class-form/resource-class-form.component.ts b/apps/dsp-app/src/app/project/ontology/resource-class-form/resource-class-form.component.ts index 800be325c6..e69d31b30a 100644 --- a/apps/dsp-app/src/app/project/ontology/resource-class-form/resource-class-form.component.ts +++ b/apps/dsp-app/src/app/project/ontology/resource-class-form/resource-class-form.component.ts @@ -1,15 +1,15 @@ -import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { FormBuilder, Validators } from '@angular/forms'; import { ClassDefinition, PropertyDefinition } from '@dasch-swiss/dsp-js'; import { getAllEntityDefinitionsAsArray } from '@dasch-swiss/vre/shared/app-api'; import { OntologyService } from '@dasch-swiss/vre/shared/app-helper-services'; import { OntologiesSelectors } from '@dasch-swiss/vre/shared/app-state'; -import { MultiLanguageFormArray } from '@dasch-swiss/vre/shared/app-string-literal'; +import { DEFAULT_MULTILANGUAGE_FORM, MultiLanguages } from '@dasch-swiss/vre/shared/app-string-literal'; import { Store } from '@ngxs/store'; -import { Subscription } from 'rxjs'; import { existingNamesValidator } from '../../../main/directive/existing-name/existing-names.validator'; import { atLeastOneStringRequired } from '../../../main/form-validators/at-least-one-string-required.validator'; import { CustomRegex } from '../../../workspace/resource/values/custom-regex'; +import { ResourceClassForm } from './resource-class-form.type'; @Component({ selector: 'app-resource-class-form', @@ -26,14 +26,14 @@ import { CustomRegex } from '../../../workspace/resource/values/custom-regex'; @@ -41,27 +41,17 @@ import { CustomRegex } from '../../../workspace/resource/values/custom-regex'; `, styles: [':host ::ng-deep .name-input .mat-icon { padding-right: 24px; }'], }) -export class ResourceClassFormComponent implements OnInit, OnDestroy { +export class ResourceClassFormComponent implements OnInit { @Input() formData: { name: string; - labels: { language: string; value: string }[]; - comments: { language: string; value: string }[]; + labels: MultiLanguages; + comments: MultiLanguages; }; - @Output() formValueChange = new EventEmitter(); + @Output() afterFormInit = new EventEmitter(); - // TODO remove with typed forms - get commentsControl() { - return this.form.get('comments') as MultiLanguageFormArray; - } - - get labelsControl() { - return this.form.get('labels') as MultiLanguageFormArray; - } - - form: FormGroup; - existingNames: [RegExp] = [new RegExp('anEmptyRegularExpressionWasntPossible')]; + form: ResourceClassForm; ontology; - subscription: Subscription; + readonly existingNames: [RegExp] = [new RegExp('anEmptyRegularExpressionWasntPossible')]; readonly labelsValidators = [Validators.maxLength(2000)]; readonly commentsValidators = [Validators.maxLength(2000)]; @@ -90,10 +80,7 @@ export class ResourceClassFormComponent implements OnInit, OnDestroy { this.buildForm(); - this.subscription = this.form.valueChanges.subscribe(z => { - this.formValueChange.emit(this.form); - }); - this.formValueChange.emit(this.form); + this.afterFormInit.emit(this.form); } buildForm() { @@ -106,28 +93,12 @@ export class ResourceClassFormComponent implements OnInit, OnDestroy { Validators.pattern(CustomRegex.ID_NAME_REGEX), ], ], - labels: this._fb.array( - this.formData.labels.map(({ language, value }) => - this._fb.group({ - language, - value: [value, this.labelsValidators], - }) - ), - atLeastOneStringRequired('value') - ), - comments: this._fb.array( - this.formData.comments.map(({ language, value }) => - this._fb.group({ - language, - value: [value, this.commentsValidators], - }) - ), - atLeastOneStringRequired('value') - ), + labels: DEFAULT_MULTILANGUAGE_FORM(this.formData.labels, this.labelsValidators, [ + atLeastOneStringRequired('value'), + ]), + comments: DEFAULT_MULTILANGUAGE_FORM(this.formData.comments, this.commentsValidators, [ + atLeastOneStringRequired('value'), + ]), }); } - - ngOnDestroy() { - this.subscription.unsubscribe(); - } } diff --git a/apps/dsp-app/src/app/project/ontology/resource-class-form/resource-class-form.type.ts b/apps/dsp-app/src/app/project/ontology/resource-class-form/resource-class-form.type.ts new file mode 100644 index 0000000000..884430499f --- /dev/null +++ b/apps/dsp-app/src/app/project/ontology/resource-class-form/resource-class-form.type.ts @@ -0,0 +1,8 @@ +import { FormControl, FormGroup } from '@angular/forms'; +import { MultiLanguageFormArray } from '@dasch-swiss/vre/shared/app-string-literal'; + +export type ResourceClassForm = FormGroup<{ + name: FormControl; + labels: MultiLanguageFormArray; + comments: MultiLanguageFormArray; +}>; diff --git a/apps/dsp-app/src/app/project/reusable-project-form/project-form.type.ts b/apps/dsp-app/src/app/project/reusable-project-form/project-form.type.ts new file mode 100644 index 0000000000..b7d95a43b1 --- /dev/null +++ b/apps/dsp-app/src/app/project/reusable-project-form/project-form.type.ts @@ -0,0 +1,10 @@ +import { FormArray, FormControl, FormGroup } from '@angular/forms'; +import { MultiLanguageFormArray } from '@dasch-swiss/vre/shared/app-string-literal'; + +export type ProjectForm = FormGroup<{ + shortcode: FormControl; + shortname: FormControl; + longname: FormControl; + description: MultiLanguageFormArray; + keywords: FormArray>; +}>; diff --git a/apps/dsp-app/src/app/project/reusable-project-form/reusable-project-form.component.ts b/apps/dsp-app/src/app/project/reusable-project-form/reusable-project-form.component.ts index f79a5ba53d..4c4ae48960 100644 --- a/apps/dsp-app/src/app/project/reusable-project-form/reusable-project-form.component.ts +++ b/apps/dsp-app/src/app/project/reusable-project-form/reusable-project-form.component.ts @@ -1,12 +1,11 @@ -import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { FormBuilder, Validators } from '@angular/forms'; import { ProjectsSelectors } from '@dasch-swiss/vre/shared/app-state'; -import { MultiLanguageFormArray, MultiLanguages } from '@dasch-swiss/vre/shared/app-string-literal'; +import { DEFAULT_MULTILANGUAGE_FORM, MultiLanguages } from '@dasch-swiss/vre/shared/app-string-literal'; import { Store } from '@ngxs/store'; -import { Subscription } from 'rxjs'; -import { startWith } from 'rxjs/operators'; import { arrayLengthGreaterThanZeroValidator } from '../../main/form-validators/array-length-greater-than-zero-validator'; import { atLeastOneStringRequired } from '../../main/form-validators/at-least-one-string-required.validator'; +import { ProjectForm } from './project-form.type'; import { shortcodeExistsValidator } from './shortcode-exists.validator'; @Component({ @@ -38,9 +37,9 @@ import { shortcodeExistsValidator } from './shortcode-exists.validator'; + [formArray]="form.controls.description" + [validators]="descriptionValidators" + data-cy="description-input"> @@ -49,7 +48,7 @@ import { shortcodeExistsValidator } from './shortcode-exists.validator'; `, }) -export class ReusableProjectFormComponent implements OnInit, OnDestroy { +export class ReusableProjectFormComponent implements OnInit { @Input() formData: { shortcode: string; shortname: string; @@ -57,19 +56,16 @@ export class ReusableProjectFormComponent implements OnInit, OnDestroy { description: MultiLanguages; keywords: string[]; }; - @Output() formValueChange = new EventEmitter(); + @Output() afterFormInit = new EventEmitter(); - // TODO remove with typed forms - get descriptionControl() { - return this.form.get('description') as MultiLanguageFormArray; - } - - form: FormGroup; - shortcodePatternError = { errorKey: 'pattern', message: 'This field must contains letters from A to F and 0 to 9' }; - shortCodeExistsError = { errorKey: 'shortcodeExists', message: 'This shortcode already exists' }; + form: ProjectForm; + readonly shortcodePatternError = { + errorKey: 'pattern', + message: 'This field must contains letters from A to F and 0 to 9', + }; + readonly shortCodeExistsError = { errorKey: 'shortcodeExists', message: 'This shortcode already exists' }; readonly keywordsValidators = [Validators.minLength(3), Validators.maxLength(64)]; readonly descriptionValidators = [Validators.minLength(3), Validators.maxLength(40960)]; - subscription: Subscription; constructor( private _fb: FormBuilder, @@ -78,10 +74,7 @@ export class ReusableProjectFormComponent implements OnInit, OnDestroy { ngOnInit() { this._buildForm(); - - this.subscription = this.form.valueChanges.pipe(startWith(null)).subscribe(() => { - this.formValueChange.emit(this.form); - }); + this.afterFormInit.emit(this.form); } private _buildForm() { @@ -103,15 +96,9 @@ export class ReusableProjectFormComponent implements OnInit, OnDestroy { [Validators.required, Validators.minLength(3), Validators.maxLength(20), Validators.pattern(/^[a-zA-Z]+\S*$/)], ], longname: [this.formData.longname, [Validators.required, Validators.minLength(3), Validators.maxLength(256)]], - description: this._fb.array( - this.formData.description.map(({ language, value }) => - this._fb.group({ - language, - value: [value, this.descriptionValidators], - }) - ), - atLeastOneStringRequired('value') - ), + description: DEFAULT_MULTILANGUAGE_FORM(this.formData.description, this.descriptionValidators, [ + atLeastOneStringRequired('value'), + ]), keywords: this._fb.array( this.formData.keywords.map(keyword => { return [keyword, this.keywordsValidators]; @@ -120,8 +107,4 @@ export class ReusableProjectFormComponent implements OnInit, OnDestroy { ), }); } - - ngOnDestroy() { - this.subscription.unsubscribe(); - } } diff --git a/libs/vre/shared/app-string-literal/src/index.ts b/libs/vre/shared/app-string-literal/src/index.ts index 0ca22d31d9..975d9297e5 100644 --- a/libs/vre/shared/app-string-literal/src/index.ts +++ b/libs/vre/shared/app-string-literal/src/index.ts @@ -5,3 +5,4 @@ export * from './lib/human-readable-error.pipe'; export * from './lib/multi-languages.type'; export * from './lib/multi-language-form-array.type'; export * from './lib/dash-language.type'; +export * from './lib/default-multi-language-form'; diff --git a/libs/vre/shared/app-string-literal/src/lib/default-multi-language-form.ts b/libs/vre/shared/app-string-literal/src/lib/default-multi-language-form.ts new file mode 100644 index 0000000000..4aecb11a07 --- /dev/null +++ b/libs/vre/shared/app-string-literal/src/lib/default-multi-language-form.ts @@ -0,0 +1,20 @@ +import { FormArray, FormControl, FormGroup, ValidatorFn } from '@angular/forms'; +import { StringLiteralV2 } from '@dasch-swiss/vre/open-api'; +import { DaschLanguage } from './dash-language.type'; + +export const DEFAULT_MULTILANGUAGE_FORM = ( + data: StringLiteralV2[], + controlValidators?: ValidatorFn[], + arrayValidators?: ValidatorFn[] +) => { + return new FormArray( + data.map( + item => + new FormGroup({ + language: new FormControl(item.language as DaschLanguage), + value: new FormControl(item.value, { validators: controlValidators }), + }) + ), + arrayValidators + ); +};