fix bugs: saving extra fields in dmp, showing draft blueprints when min or max of a description template are not set

This commit is contained in:
Bernaldo Mihasi 2023-09-20 09:34:39 +03:00
parent 93c5918251
commit 367861c050
13 changed files with 156 additions and 67 deletions

View File

@ -1958,15 +1958,15 @@ public class DataManagementPlanManager {
// Creates new dataManagementPlan to fill it with the data model that was parsed from the xml.
// Creates properties.
DataManagementPlanEditorModel dm = new DataManagementPlanEditorModel();
DataManagementPlanProfile dmpProfile = new DataManagementPlanProfile();
List<Field> fieldList = new LinkedList<>();
Field field = new Field();
field.setLabel(dataManagementPlans.get(0).getDmpProfile().getDmpProfileName());
field.setId(dataManagementPlans.get(0).getDmpProfile().getDmpProfileId());
fieldList.add(field);
dmpProfile.setFields(fieldList);
// DataManagementPlanProfile dmpProfile = new DataManagementPlanProfile();
//
// List<Field> fieldList = new LinkedList<>();
// Field field = new Field();
// field.setLabel(dataManagementPlans.get(0).getDmpProfile().getDmpProfileName());
// field.setId(dataManagementPlans.get(0).getDmpProfile().getDmpProfileId());
//
// fieldList.add(field);
// dmpProfile.setFields(fieldList);
/*Tuple tuple = new Tuple();
tuple.setId(dataManagementPlans.get(0).getDmpProfile().getDmpProfileId());
@ -2043,7 +2043,7 @@ public class DataManagementPlanManager {
dm.setResearchers(researchers); // Sets researchers property.
dm.setAssociatedUsers(associatedUsers); // Sets associatedUsers property.
dm.setDynamicFields(dynamicFields); // Sets dynamicFields property.
dm.setDefinition(dmpProfile);
//dm.setDefinition(dmpProfile);
//ObjectMapper mapper = new ObjectMapper();
Map<String, Object> extraPropertiesMap = new HashMap<>();
if (dataManagementPlans.get(0).getLanguage() != null) {

View File

@ -35,7 +35,7 @@ public class DataManagementPlan implements DataModel<DMP, DataManagementPlan> {
private List<Organisation> organisations;
private List<Researcher> researchers;
private List<UserListingModel> associatedUsers;
private DataManagementPlanProfile definition;
private List<ExtraFieldModel> extraFields;
private eu.eudat.models.data.userinfo.UserInfo creator;
private Date modified;
private Date created;
@ -153,11 +153,11 @@ public class DataManagementPlan implements DataModel<DMP, DataManagementPlan> {
this.description = description;
}
public DataManagementPlanProfile getDefinition() {
return definition;
public List<ExtraFieldModel> getExtraFields() {
return extraFields;
}
public void setDefinition(DataManagementPlanProfile definition) {
this.definition = definition;
public void setExtraFields(List<ExtraFieldModel> extraFields) {
this.extraFields = extraFields;
}
public Map<String, Object> getProperties() {
@ -253,11 +253,13 @@ public class DataManagementPlan implements DataModel<DMP, DataManagementPlan> {
this.creator = new eu.eudat.models.data.userinfo.UserInfo();
this.groupId = entity.getGroupId();
this.lockable = entity.getDataset() != null && entity.getDataset().stream().findAny().isPresent();
this.definition = entity.getProfile() == null ? null : new DataManagementPlanProfile().fromXml(XmlBuilder.fromXml(entity.getProfile().getDefinition()).getDocumentElement());
if (this.definition != null && this.definition.getFields() != null && !this.definition.getFields().isEmpty() && this.properties != null) {
this.definition.getFields().forEach(item -> {
Optional<Map<String, Object>> fieldOptional = ((List<Map<String, Object>>) this.properties.get("fields")).stream().filter(field -> field.get("id").equals(item.getId().toString())).findFirst();
if (fieldOptional.isPresent()) item.setValue(fieldOptional.get().get("value"));
if (this.properties != null) {
this.extraFields = new ArrayList<>();
this.properties.forEach((id, value) -> {
ExtraFieldModel extraField = new ExtraFieldModel();
extraField.setId(id);
extraField.setValue(value.toString());
this.extraFields.add(extraField);
});
}
if (entity.getUsers() != null && entity.getUsers().stream().anyMatch(userDMP -> userDMP.getRole().equals(UserDMP.UserDMPRoles.OWNER.getValue())))
@ -345,6 +347,9 @@ public class DataManagementPlan implements DataModel<DMP, DataManagementPlan> {
}
dataManagementPlanEntity.setAssociatedDmps(dmpDatasetProfiles);
}
if(this.extraFields != null) {
this.properties = this.extraFields.stream().collect(Collectors.toMap(ExtraFieldModel::getId, ExtraFieldModel::getValue));
}
dataManagementPlanEntity.setProperties(this.properties != null ? JSONObject.toJSONString(this.properties) : null);
dataManagementPlanEntity.setGroupId(this.groupId != null ? this.groupId : UUID.randomUUID());
dataManagementPlanEntity.setModified(this.modified != null ? this.modified : new Date());
@ -371,11 +376,13 @@ public class DataManagementPlan implements DataModel<DMP, DataManagementPlan> {
this.creator = new eu.eudat.models.data.userinfo.UserInfo();
this.groupId = entity.getGroupId();
this.lockable = entity.getDataset() != null && entity.getDataset().stream().findAny().isPresent();
this.definition = entity.getProfile() == null ? null : new DataManagementPlanProfile().fromXml(XmlBuilder.fromXml(entity.getProfile().getDefinition()).getDocumentElement());
if (this.definition != null && this.definition.getFields() != null && !this.definition.getFields().isEmpty() && this.properties != null) {
this.definition.getFields().forEach(item -> {
Optional<Map<String, Object>> fieldOptional = ((List<Map<String, Object>>) this.properties.get("fields")).stream().filter(field -> field.get("id").equals(item.getId().toString())).findFirst();
fieldOptional.ifPresent(stringObjectMap -> item.setValue(stringObjectMap.get("value")));
if (this.properties != null) {
this.extraFields = new ArrayList<>();
this.properties.forEach((id, value) -> {
ExtraFieldModel extraField = new ExtraFieldModel();
extraField.setId(id);
extraField.setValue(value.toString());
this.extraFields.add(extraField);
});
}
if (entity.getUsers() != null && entity.getUsers().stream().anyMatch(userDMP -> userDMP.getRole().equals(UserDMP.UserDMPRoles.OWNER.getValue())))

View File

@ -34,7 +34,7 @@ public class DataManagementPlanEditorModel implements DataModel<DMP, DataManagem
private List<Organisation> organisations;
private List<Researcher> researchers;
private List<UserListingModel> associatedUsers;
private DataManagementPlanProfile definition;
private List<ExtraFieldModel> extraFields;
private eu.eudat.models.data.userinfo.UserInfo creator;
private Date modified;
private Date created;
@ -151,11 +151,11 @@ public class DataManagementPlanEditorModel implements DataModel<DMP, DataManagem
this.description = description;
}
public DataManagementPlanProfile getDefinition() {
return definition;
public List<ExtraFieldModel> getExtraFields() {
return extraFields;
}
public void setDefinition(DataManagementPlanProfile definition) {
this.definition = definition;
public void setExtraFields(List<ExtraFieldModel> extraFields) {
this.extraFields = extraFields;
}
public Map<String, Object> getProperties() {
@ -239,11 +239,13 @@ public class DataManagementPlanEditorModel implements DataModel<DMP, DataManagem
this.creator = new eu.eudat.models.data.userinfo.UserInfo();
this.groupId = entity.getGroupId();
this.lockable = entity.getDataset().stream().findAny().isPresent();
this.definition = entity.getProfile() == null ? null : new DataManagementPlanProfile().fromXml(XmlBuilder.fromXml(entity.getProfile().getDefinition()).getDocumentElement());
if (this.definition != null && this.definition.getFields() != null && !this.definition.getFields().isEmpty() && this.properties != null) {
this.definition.getFields().forEach(item -> {
Optional<Map<String, Object>> fieldOptional = ((List<Map<String, Object>>) this.properties.get("fields")).stream().filter(field -> field.get("id").equals(item.getId().toString())).findFirst();
if (fieldOptional.isPresent()) item.setValue(fieldOptional.get().get("value"));
if (this.properties != null) {
this.extraFields = new ArrayList<>();
this.properties.forEach((id, value) -> {
ExtraFieldModel extraField = new ExtraFieldModel();
extraField.setId(id);
extraField.setValue(value.toString());
this.extraFields.add(extraField);
});
}
if (entity.getUsers().stream().anyMatch(userDMP -> userDMP.getRole().equals(UserDMP.UserDMPRoles.OWNER.getValue())))
@ -371,6 +373,9 @@ public class DataManagementPlanEditorModel implements DataModel<DMP, DataManagem
}
dataManagementPlanEntity.setAssociatedDmps(dmpDatasetProfiles);
}
if(this.extraFields != null) {
this.properties = this.extraFields.stream().collect(Collectors.toMap(ExtraFieldModel::getId, ExtraFieldModel::getValue));
}
dataManagementPlanEntity.setProperties(this.properties != null ? JSONObject.toJSONString(this.properties) : null);
dataManagementPlanEntity.setGroupId(this.groupId != null ? this.groupId : UUID.randomUUID());
dataManagementPlanEntity.setModified(this.modified != null ? this.modified : new Date());

View File

@ -0,0 +1,20 @@
package eu.eudat.models.data.dmp;
public class ExtraFieldModel {
private String id;
private String value;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@ -65,8 +65,8 @@ public class DescriptionTemplate implements XmlSerializable<DescriptionTemplate>
this.id = UUID.fromString(item.getAttribute("id"));
this.descriptionTemplateId = UUID.fromString(item.getAttribute("descriptionTemplateId"));
this.label = item.getAttribute("label");
this.minMultiplicity = Integer.valueOf(item.getAttribute("minMultiplicity"));
this.maxMultiplicity = Integer.valueOf(item.getAttribute("maxMultiplicity"));
this.minMultiplicity = item.hasAttribute("minMultiplicity") && !item.getAttribute("minMultiplicity").equals("null") ? Integer.parseInt(item.getAttribute("minMultiplicity")) : null;
this.maxMultiplicity = item.hasAttribute("maxMultiplicity") && !item.getAttribute("minMultiplicity").equals("null") ? Integer.parseInt(item.getAttribute("maxMultiplicity")) : null;
return this;
}
}

View File

@ -190,7 +190,7 @@ public class DataManagementPlanOverviewModel implements DataModel<DMP, DataManag
public DataManagementPlanOverviewModel fromDataModelDatasets(DMP entity) {
this.fromDataModel(entity);
this.version = entity.getVersion();
this.grant = new GrantOverviewModel().fromDataModel(entity.getGrant());
if (entity.getGrant() != null) this.grant = new GrantOverviewModel().fromDataModel(entity.getGrant());
if (entity.getProfile() != null) this.profile = entity.getProfile().getLabel();
this.creationTime = entity.getCreated();
this.modifiedTime = entity.getModified();

View File

@ -0,0 +1,4 @@
export interface DmpExtraField {
id: string;
value: string;
}

View File

@ -10,6 +10,7 @@ import { FunderModel } from "../funder/funder";
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { DatasetWizardModel } from '../dataset/dataset-wizard';
import { DmpDatasetProfile } from "./dmp-dataset-profile/dmp-dataset-profile";
import { DmpExtraField } from "./dmp-extra-field";
export interface DmpModel {
id: string;
@ -31,7 +32,7 @@ export interface DmpModel {
associatedUsers: UserModel[];
users: UserInfoListingModel[];
creator: UserModel;
definition: DmpProfileDefinition;
extraFields: Array<DmpExtraField>;
dynamicFields: Array<DmpDynamicField>;
modified: Date;
extraProperties: Map<String, any>;

View File

@ -268,26 +268,26 @@
</div> -->
</div>
<div *ngIf="field.category === 'EXTRA'">
<div *ngIf="field.type == 'TEXT'">
<div *ngIf="field.type === extraFieldTypesEnum.TEXT">
<mat-form-field>
<input matInput placeholder="field.placeholder" type="text" name="label" [formControl]="label" [required]="field.required">
<input matInput placeholder="{{field.placeholder}}" type="text" name="value" [formControl]="formGroup.get('extraFields').get(getExtraFieldIndex(field.id)).get('value')" [required]="field.required">
</mat-form-field>
</div>
<div *ngIf="field.type == 'RICH_TEXT'">
<div *ngIf="field.type === extraFieldTypesEnum.RICH_TEXT">
<mat-form-field>
<!-- <rich-text-editor-component [parentFormGroup]="formGroup" [controlName]="'label'"
[placeholder]="field.placeholder">
</rich-text-editor-component> -->
</mat-form-field>
</div>
<div *ngIf="field.type == 'DATE'">
<div *ngIf="field.type === extraFieldTypesEnum.DATE">
<mat-form-field>
<input matInput placeholder="field.placeholder" type="date" name="label" [formControl]="label" [required]="field.required">
<input matInput placeholder="{{field.placeholder}}" type="date" name="value" [formControl]="formGroup.get('extraFields').get(getExtraFieldIndex(field.id)).get('value')" [required]="field.required">
</mat-form-field>
</div>
<div *ngIf="field.type == 'NUMBER'">
<div *ngIf="field.type === extraFieldTypesEnum.NUMBER">
<mat-form-field>
<input matInput placeholder="field.placeholder" type="number" name="label" [formControl]="label" [required]="field.required">
<input matInput placeholder="{{field.placeholder}}" type="number" name="value" [formControl]="formGroup.get('extraFields').get(getExtraFieldIndex(field.id)).get('value')" [required]="field.required">
</mat-form-field>
</div>
</div>

View File

@ -1,13 +1,13 @@
import { Component, OnInit } from '@angular/core';
import { AbstractControl, FormArray, FormControl, FormGroup, Validators } from '@angular/forms';
import { AbstractControl, FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DmpBlueprintDefinition, FieldCategory, SystemFieldType } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint';
import { DmpBlueprintDefinition, ExtraFieldType, FieldCategory, SystemFieldType } from '@app/core/model/dmp/dmp-blueprint/dmp-blueprint';
import { DmpBlueprintCriteria } from '@app/core/query/dmp/dmp-blueprint-criteria';
import { DmpProfileService } from '@app/core/services/dmp/dmp-profile.service';
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
import { DmpBlueprintEditor } from '@app/ui/admin/dmp-profile/editor/dmp-blueprint-editor.model';
import { debounceTime, filter, map, switchMap, takeUntil, tap } from 'rxjs/operators';
import { DmpEditorModel } from '../editor/dmp-editor.model';
import { DmpEditorModel, DmpExtraFieldEditorModel } from '../editor/dmp-editor.model';
import { ExtraPropertiesFormModel } from '../editor/general-tab/extra-properties-form.model';
import { FunderFormModel } from '../editor/grant-tab/funder-form-model';
import { GrantTabModel } from '../editor/grant-tab/grant-tab-model';
@ -109,6 +109,8 @@ export class DmpEditorBlueprintComponent extends CheckDeactivateBaseComponent im
sectionTemplates: Array<Array<DatasetProfileModel>> = new Array<Array<DatasetProfileModel>>();
extraFieldTypesEnum = ExtraFieldType;
private associates: UserModel[] = [];
visibles: Visible[] = [
@ -181,6 +183,7 @@ export class DmpEditorBlueprintComponent extends CheckDeactivateBaseComponent im
this.checkForGrant();
this.checkForFunder();
this.checkForProject();
this.buildExtraFields();
this.formGroup.get('profile').setValue(result);
this.maxStep = this.selectedDmpBlueprintDefinition.sections.length;
this.step = 1;
@ -248,6 +251,10 @@ export class DmpEditorBlueprintComponent extends CheckDeactivateBaseComponent im
.pipe(takeUntil(this._destroyed))
.subscribe(result => {
this.selectedDmpBlueprintDefinition = result.definition;
this.checkForGrant();
this.checkForFunder();
this.checkForProject();
this.buildExtraFields();
this.formGroup.get('profile').setValue(result);
this.maxStep = this.selectedDmpBlueprintDefinition.sections.length;
this.step = 1;
@ -790,6 +797,7 @@ export class DmpEditorBlueprintComponent extends CheckDeactivateBaseComponent im
this.checkForGrant();
this.checkForFunder();
this.checkForProject();
this.buildExtraFields();
this.addProfiles();
}
else {
@ -798,6 +806,31 @@ export class DmpEditorBlueprintComponent extends CheckDeactivateBaseComponent im
})
}
private buildExtraFields(): void {
const extraFields = new Array<FormGroup>();
this.selectedDmpBlueprintDefinition.sections.forEach(section => section.fields.forEach(field => {
if (field.category as unknown == 'EXTRA') {
let extraField = new DmpExtraFieldEditorModel();
extraField.id = field.id;
if (!isNullOrUndefined(this.dmp.extraFields)) {
extraField.value = this.dmp.extraFields.find(f => f.id === field.id).value;
}
extraFields.push(extraField.buildForm());
}
}));
this.formGroup.setControl('extraFields', new FormBuilder().array(extraFields));
}
getExtraFieldIndex(id: string): string {
let foundFieldIndex: number;
(this.formGroup.get('extraFields') as FormArray).controls.forEach((element, index) => {
if(element.value.id === id) {
foundFieldIndex = index;
}
});
return foundFieldIndex.toString();
}
private checkForGrant() {
let hasGrant = false;
this.selectedDmpBlueprintDefinition.sections.forEach(section => section.fields.forEach(

View File

@ -2,7 +2,6 @@ import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { DmpProfileFieldDataType } from '@app/core/common/enum/dmp-profile-field-type';
import { DmpProfileType } from '@app/core/common/enum/dmp-profile-type';
import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile';
import { DmpProfileField } from '@app/core/model/dmp-profile/dmp-profile-field';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { DmpDynamicField } from '@app/core/model/dmp/dmp-dynamic-field';
@ -23,6 +22,7 @@ import { ExtraPropertiesFormModel } from './general-tab/extra-properties-form.mo
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model';
import { DmpDatasetProfile } from "@app/core/model/dmp/dmp-dataset-profile/dmp-dataset-profile";
import { DmpExtraField } from "@app/core/model/dmp/dmp-extra-field";
export class DmpEditorModel {
public id: string;
@ -45,7 +45,7 @@ export class DmpEditorModel {
public datasetsToBeFinalized: string[] = [];
public associatedUsers: UserModel[] = [];
public users: UserInfoListingModel[] = [];
public definition: DmpProfileDefinition;
public extraFields: Array<DmpExtraFieldEditorModel> = [];
public dynamicFields: Array<DmpDynamicFieldEditorModel> = [];
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
public modified: Date;
@ -70,7 +70,7 @@ export class DmpEditorModel {
this.datasetsToBeFinalized = item.datasetsToBeFinalized;
this.associatedUsers = item.associatedUsers;
this.users = item.users;
if (item.definition) { this.definition = item.definition; }
if (item.extraFields) { item.extraFields.map(x => this.extraFields.push(new DmpExtraFieldEditorModel().fromModel(x))); }
if (item.dynamicFields) { item.dynamicFields.map(x => this.dynamicFields.push(new DmpDynamicFieldEditorModel().fromModel(x))); }
this.creator = item.creator;
this.modified = new Date(item.modified);
@ -113,14 +113,9 @@ export class DmpEditorModel {
if (this.dynamicFields) { this.dynamicFields.forEach(item => dynamicFields.push(item.buildForm())); }
formGroup.addControl('dynamicFields', new FormBuilder().array(dynamicFields));
if (this.definition) {
const fields = new Array<FormGroup>();
this.definition.fields.forEach(item => fields.push(new DmpDefinitionFieldEditorModel().fromModel(item).buildForm()));
const definition = new FormBuilder().group({
fields: new FormBuilder().array(fields)
});
formGroup.addControl('definition', definition);
}
const extraFields = new Array<FormGroup>();
if (this.extraFields) { this.extraFields.forEach(item => extraFields.push(item.buildForm())); }
formGroup.addControl('extraFields', new FormBuilder().array(extraFields));
return formGroup;
}
@ -149,6 +144,26 @@ export class DmpEditorModel {
}
}
export class DmpExtraFieldEditorModel {
public id: string;
public value: string;
fromModel(item: DmpExtraField): DmpExtraFieldEditorModel {
this.id = item.id;
this.value = item.value;
return this;
}
buildForm(): FormGroup {
const builder = new FormBuilder();
const formGroup = builder.group({
id: [this.id],
value: [this.value]
});
return formGroup;
}
}
export class DmpDynamicFieldEditorModel {
public id: string;

View File

@ -61,8 +61,10 @@
<mat-icon class="mat-mini-fab-icon">delete</mat-icon>
</button>
</div>
<div class="row header">{{'DMP-OVERVIEW.GRANT' | translate}}</div>
<div class="row dmp-label">{{ dmp.grant.label }}</div>
<div *ngIf="dmp.grant">
<div class="row header">{{'DMP-OVERVIEW.GRANT' | translate}}</div>
<div class="row dmp-label">{{ dmp.grant.label }}</div>
</div>
<div class="row header">{{'DMP-OVERVIEW.RESEARCHERS' | translate}}</div>
<div class="row">
<div *ngFor="let researcher of dmp.researchers; let last = last">

View File

@ -1,6 +1,4 @@
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
import { Status } from '@app/core/common/enum/status';
import { DmpProfile, DmpProfileDefinition } from '@app/core/model/dmp-profile/dmp-profile';
import { DmpModel } from '@app/core/model/dmp/dmp';
import { DmpDynamicField } from '@app/core/model/dmp/dmp-dynamic-field';
import { DmpDynamicFieldDependency } from '@app/core/model/dmp/dmp-dynamic-field-dependency';
@ -18,6 +16,7 @@ import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { ExtraPropertiesFormModel } from '../editor/general-tab/extra-properties-form.model';
import { UserInfoListingModel } from '@app/core/model/user/user-info-listing';
import { DmpDatasetProfile } from "@app/core/model/dmp/dmp-dataset-profile/dmp-dataset-profile";
import { DmpExtraFieldEditorModel } from "../editor/dmp-editor.model";
export class DmpWizardEditorModel {
public id: string;
@ -37,7 +36,7 @@ export class DmpWizardEditorModel {
public profiles: DmpDatasetProfile[] = [];
public associatedUsers: UserModel[] = [];
public users: UserInfoListingModel[] = [];
public definition: DmpProfileDefinition;
public extraFields: Array<DmpExtraFieldEditorModel> = [];
public dynamicFields: Array<DmpDynamicFieldEditorModel> = [];
public validationErrorModel: ValidationErrorModel = new ValidationErrorModel();
public extraProperties: ExtraPropertiesFormModel;
@ -59,7 +58,7 @@ export class DmpWizardEditorModel {
this.profiles = item.profiles;
this.associatedUsers = item.associatedUsers;
this.users = item.users;
if (item.definition) { this.definition = item.definition; }
if (item.extraFields) { item.extraFields.map(x => this.extraFields.push(new DmpExtraFieldEditorModel().fromModel(x))); }
if (item.dynamicFields) { item.dynamicFields.map(x => this.dynamicFields.push(new DmpDynamicFieldEditorModel().fromModel(x))); }
this.creator = item.creator;
this.extraProperties.fromModel(item.extraProperties);
@ -91,9 +90,12 @@ export class DmpWizardEditorModel {
const dynamicFields = new Array<FormGroup>();
if (this.dynamicFields) { this.dynamicFields.forEach(item => dynamicFields.push(item.buildForm())); }
formGroup.addControl('dynamicFields', new FormBuilder().array(dynamicFields));
const extraFields = new Array<FormGroup>();
if (this.extraFields) { this.extraFields.forEach(item => extraFields.push(item.buildForm())); }
formGroup.addControl('extraFields', new FormBuilder().array(extraFields));
return formGroup;
}