diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html
index 0ab69851a5..cb00993324 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.html
@@ -11,13 +11,12 @@
'd-none': value?.isVirtual && (model.hasSelectableMetadata || context?.index > 0)}">
+
-
-
0 && context?.index < context?.context?.groups?.length - 1)
- && (!showErrorMessages || errorMessages.length === 0)"
- class="text-muted" [ngClass]="getClass('element', 'hint')">
+
+
0
+ && (!showErrorMessages || errorMessages.length === 0)" class="clearfix w-100 mb-2">
{{ message | translate: model.validators }}
@@ -37,14 +36,6 @@
-
0">
-
-
@@ -70,6 +61,7 @@
[relationshipOptions]="model.relationship"
>
+
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts
index 72dd374231..6c080a7f53 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control-container.component.ts
@@ -37,7 +37,6 @@ import {
DynamicFormControl,
DynamicFormControlContainerComponent,
DynamicFormControlEvent,
- DynamicFormControlEventType,
DynamicFormControlModel,
DynamicFormLayout,
DynamicFormLayoutService,
@@ -83,18 +82,16 @@ import { find, map, startWith, switchMap, take } from 'rxjs/operators';
import { combineLatest as observableCombineLatest, Observable, Subscription } from 'rxjs';
import { SearchResult } from '../../../search/search-result.model';
import { DSpaceObject } from '../../../../core/shared/dspace-object.model';
-import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { RelationshipService } from '../../../../core/data/relationship.service';
import { SelectableListService } from '../../../object-list/selectable-list/selectable-list.service';
import { DsDynamicDisabledComponent } from './models/disabled/dynamic-disabled.component';
import { DYNAMIC_FORM_CONTROL_TYPE_DISABLED } from './models/disabled/dynamic-disabled.model';
-import { DsDynamicLookupRelationModalComponent } from './relation-lookup-modal/dynamic-lookup-relation-modal.component';
import {
getAllSucceededRemoteData,
+ getFirstSucceededRemoteData,
getFirstSucceededRemoteDataPayload,
getPaginatedListPayload,
- getRemoteDataPayload,
- getFirstSucceededRemoteData
+ getRemoteDataPayload
} from '../../../../core/shared/operators';
import { RemoteData } from '../../../../core/data/remote-data';
import { Item } from '../../../../core/shared/item.model';
@@ -110,7 +107,6 @@ import { Collection } from '../../../../core/shared/collection.model';
import { MetadataValue, VIRTUAL_METADATA_PREFIX } from '../../../../core/shared/metadata.models';
import { FormService } from '../../form.service';
import { SelectableListState } from '../../../object-list/selectable-list/selectable-list.reducer';
-import { SubmissionService } from '../../../../submission/submission.service';
import { followLink } from '../../../utils/follow-link-config.model';
import { paginatedRelationsToItems } from '../../../../+item-page/simple/item-types/shared/item-relationships-utils';
import { RelationshipOptions } from '../models/relationship-options.model';
@@ -206,7 +202,6 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
@Input() model: any;
relationshipValue$: Observable;
isRelationship: boolean;
- modalRef: NgbModalRef;
item: Item;
item$: Observable- ;
collection: Collection;
@@ -239,7 +234,6 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
protected validationService: DynamicFormValidationService,
protected translateService: TranslateService,
protected relationService: DynamicFormRelationService,
- private modalService: NgbModal,
private relationshipService: RelationshipService,
private selectableListService: SelectableListService,
private itemService: ItemDataService,
@@ -249,7 +243,6 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
private ref: ChangeDetectorRef,
private formService: FormService,
private formBuilderService: FormBuilderService,
- private submissionService: SubmissionService
) {
super(ref, componentFactoryResolver, layoutService, validationService, dynamicFormComponentService, relationService);
}
@@ -264,7 +257,6 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
if (this.isRelationship || isWrapperAroundRelationshipList) {
const config = this.model.relationshipConfig || this.model.relationship;
const relationshipOptions = Object.assign(new RelationshipOptions(), config);
- this.listId = `list-${this.model.submissionId}-${relationshipOptions.relationshipType}`;
this.setItem();
if (isWrapperAroundRelationshipList || !this.model.repeatable) {
@@ -378,45 +370,6 @@ export class DsDynamicFormControlContainerComponent extends DynamicFormControlCo
return this.model.value.pipe(map((list: SearchResult[]) => isNotEmpty(list)));
}
- /**
- * Open a modal where the user can select relationships to be added to item being submitted
- */
- openLookup() {
- this.modalRef = this.modalService.open(DsDynamicLookupRelationModalComponent, {
- size: 'lg'
- });
- const modalComp = this.modalRef.componentInstance;
-
- if (hasValue(this.model.value) && !this.model.readOnly) {
- if (typeof this.model.value === 'string') {
- modalComp.query = this.model.value;
- } else if (typeof this.model.value.value === 'string') {
- modalComp.query = this.model.value.value;
- }
- }
-
- if (hasValue(this.model.value)) {
- this.model.value = '';
- this.onChange({
- $event: { previousIndex: 0 },
- context: { index: 0 },
- control: this.control,
- model: this.model,
- type: DynamicFormControlEventType.Change
- });
- }
- this.submissionService.dispatchSave(this.model.submissionId);
-
- modalComp.repeatable = this.model.repeatable;
- modalComp.listId = this.listId;
- modalComp.relationshipOptions = this.model.relationship;
- modalComp.label = this.model.relationship.relationshipType;
- modalComp.metadataFields = this.model.metadataFields;
- modalComp.item = this.item;
- modalComp.collection = this.collection;
- modalComp.submissionId = this.model.submissionId;
- }
-
/**
* Callback for the remove event,
* remove the current control from its array
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.html
index 57ab7d66d8..07ea131a00 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.html
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.html
@@ -8,6 +8,7 @@
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.spec.ts
index c606145c03..3a5623cfdd 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.spec.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/existing-metadata-list-element/existing-metadata-list-element.component.spec.ts
@@ -14,6 +14,8 @@ import { createSuccessfulRemoteDataObject$ } from '../../../../remote-data.utils
import { RemoveRelationshipAction } from '../relation-lookup-modal/relationship.actions';
import { ItemSearchResult } from '../../../../object-collection/shared/item-search-result.model';
import { of as observableOf } from 'rxjs';
+import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
+import { TranslateLoaderMock } from '../../../../testing/translate-loader.mock';
describe('ExistingMetadataListElementComponent', () => {
let component: ExistingMetadataListElementComponent;
@@ -65,6 +67,14 @@ describe('ExistingMetadataListElementComponent', () => {
beforeEach(waitForAsync(() => {
init();
TestBed.configureTestingModule({
+ imports: [
+ TranslateModule.forRoot({
+ loader: {
+ provide: TranslateLoader,
+ useClass: TranslateLoaderMock
+ }
+ })
+ ],
declarations: [ExistingMetadataListElementComponent],
providers: [
{ provide: SelectableListService, useValue: selectionService },
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component.html
index ec007d6ff4..d036627345 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component.html
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/array-group/dynamic-form-array.component.html
@@ -12,7 +12,7 @@
[ngClass]="[getClass('element', 'group'), getClass('grid', 'group')]"
cdkDrag cdkDragHandle>
-
+
-
+
+
{
let component: DsDynamicLookupRelationModalComponent;
@@ -27,6 +31,7 @@ describe('DsDynamicLookupRelationModalComponent', () => {
let item;
let item1;
let item2;
+ let testWSI;
let searchResult1;
let searchResult2;
let listID;
@@ -39,6 +44,8 @@ describe('DsDynamicLookupRelationModalComponent', () => {
let externalSourceService;
let lookupRelationService;
let submissionId;
+ let submissionService;
+ let submissionObjectDataService;
const externalSources = [
Object.assign(new ExternalSource(), {
@@ -54,11 +61,16 @@ describe('DsDynamicLookupRelationModalComponent', () => {
];
const totalLocal = 10;
const totalExternal = 8;
+ const collection: Collection = new Collection();
+
function init() {
item = Object.assign(new Item(), { uuid: '7680ca97-e2bd-4398-bfa7-139a8673dc42', metadata: {} });
item1 = Object.assign(new Item(), { uuid: 'e1c51c69-896d-42dc-8221-1d5f2ad5516e' });
item2 = Object.assign(new Item(), { uuid: 'c8279647-1acc-41ae-b036-951d5f65649b' });
+ testWSI = new WorkspaceItem();
+ testWSI.item = createSuccessfulRemoteDataObject$(item);
+ testWSI.collection = createSuccessfulRemoteDataObject$(collection);
searchResult1 = Object.assign(new ItemSearchResult(), { indexableObject: item1 });
searchResult2 = Object.assign(new ItemSearchResult(), { indexableObject: item2 });
listID = '6b0c8221-fcb4-47a8-b483-ca32363fffb3';
@@ -80,6 +92,12 @@ describe('DsDynamicLookupRelationModalComponent', () => {
getTotalLocalResults: observableOf(totalLocal),
getTotalExternalResults: observableOf(totalExternal)
});
+ submissionService = jasmine.createSpyObj('SubmissionService', {
+ dispatchSave: jasmine.createSpy('dispatchSave')
+ });
+ submissionObjectDataService = jasmine.createSpyObj('SubmissionObjectDataService', {
+ findById: createSuccessfulRemoteDataObject$(testWSI)
+ });
submissionId = '1234';
}
@@ -103,6 +121,8 @@ describe('DsDynamicLookupRelationModalComponent', () => {
provide: RelationshipService, useValue: { getNameVariant: () => observableOf(nameVariant) }
},
{ provide: RelationshipTypeService, useValue: {} },
+ { provide: SubmissionService, useValue: submissionService },
+ { provide: SubmissionObjectDataService, useValue: submissionObjectDataService },
{
provide: Store, useValue: {
// tslint:disable-next-line:no-empty
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts
index 9d99bc5066..face405026 100644
--- a/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts
+++ b/src/app/shared/form/builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component.ts
@@ -24,6 +24,11 @@ import { PaginatedList } from '../../../../../core/data/paginated-list.model';
import { ExternalSource } from '../../../../../core/shared/external-source.model';
import { ExternalSourceService } from '../../../../../core/data/external-source.service';
import { Router } from '@angular/router';
+import { followLink } from '../../../../utils/follow-link-config.model';
+import { SubmissionObject } from '../../../../../core/submission/models/submission-object.model';
+import { Collection } from '../../../../../core/shared/collection.model';
+import { SubmissionService } from '../../../../../submission/submission.service';
+import { SubmissionObjectDataService } from '../../../../../core/submission/submission-object-data.service';
@Component({
selector: 'ds-dynamic-lookup-relation-modal',
@@ -113,6 +118,11 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy
*/
totalExternal$: Observable;
+ /**
+ * List of subscriptions to unsubscribe from
+ */
+ private subs: Subscription[] = [];
+
constructor(
public modal: NgbActiveModal,
private selectableListService: SelectableListService,
@@ -121,14 +131,18 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy
private externalSourceService: ExternalSourceService,
private lookupRelationService: LookupRelationService,
private searchConfigService: SearchConfigurationService,
+ private submissionService: SubmissionService,
+ private submissionObjectService: SubmissionObjectDataService,
private zone: NgZone,
private store: Store,
- private router: Router,
+ private router: Router
) {
}
ngOnInit(): void {
+ this.setItem();
+ this.submissionService.dispatchSave(this.submissionId);
this.selection$ = this.selectableListService
.getSelectableList(this.listId)
.pipe(map((listState: SelectableListState) => hasValue(listState) && hasValue(listState.selection) ? listState.selection : []));
@@ -182,6 +196,24 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy
});
}
+ /**
+ * Initialize this.item$ based on this.model.submissionId
+ */
+ private setItem() {
+ const submissionObject$ = this.submissionObjectService
+ .findById(this.submissionId, true, true, followLink('item'), followLink('collection')).pipe(
+ getAllSucceededRemoteData(),
+ getRemoteDataPayload()
+ );
+
+ const item$ = submissionObject$.pipe(switchMap((submissionObject: SubmissionObject) => (submissionObject.item as Observable>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload())));
+ const collection$ = submissionObject$.pipe(switchMap((submissionObject: SubmissionObject) => (submissionObject.collection as Observable>).pipe(getAllSucceededRemoteData(), getRemoteDataPayload())));
+
+ this.subs.push(item$.subscribe((item) => this.item = item));
+ this.subs.push(collection$.subscribe((collection) => this.collection = collection));
+
+ }
+
/**
* Add a subscription updating relationships with name variants
* @param sri The search result to track name variants for
@@ -240,5 +272,8 @@ export class DsDynamicLookupRelationModalComponent implements OnInit, OnDestroy
ngOnDestroy() {
this.router.navigate([], {});
Object.values(this.subMap).forEach((subscription) => subscription.unsubscribe());
+ this.subs
+ .filter((sub) => hasValue(sub))
+ .forEach((sub) => sub.unsubscribe());
}
}
diff --git a/src/app/shared/form/form.component.html b/src/app/shared/form/form.component.html
index 9d7a6abc47..3c28f03a88 100644
--- a/src/app/shared/form/form.component.html
+++ b/src/app/shared/form/form.component.html
@@ -12,27 +12,41 @@
(dfFocus)="onFocus($event)">
-
+
+
+
-
-
+
1"
class="col-xs-2 d-flex flex-column justify-content-sm-start align-items-end">
{{'form.discard' | translate}}
@@ -40,7 +54,6 @@
-
diff --git a/src/app/shared/form/form.component.scss b/src/app/shared/form/form.component.scss
index 01cf09576f..aafafc4a88 100644
--- a/src/app/shared/form/form.component.scss
+++ b/src/app/shared/form/form.component.scss
@@ -15,6 +15,11 @@
box-shadow: none !important;
}
+button.ds-form-add-more:focus {
+ outline: none;
+ box-shadow: none !important;
+}
+
.ds-form-input-value {
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
diff --git a/src/app/shared/form/form.component.ts b/src/app/shared/form/form.component.ts
index f749f4391b..bd742dc9c6 100644
--- a/src/app/shared/form/form.component.ts
+++ b/src/app/shared/form/form.component.ts
@@ -2,6 +2,7 @@ import { distinctUntilChanged, filter, map } from 'rxjs/operators';
import { ChangeDetectorRef, Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms';
+import { Observable, Subscription } from 'rxjs';
import {
DynamicFormArrayModel,
DynamicFormControlEvent,
@@ -9,15 +10,16 @@ import {
DynamicFormGroupModel,
DynamicFormLayout,
} from '@ng-dynamic-forms/core';
+import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { findIndex } from 'lodash';
+
import { FormBuilderService } from './builder/form-builder.service';
-import { Observable, Subscription } from 'rxjs';
import { hasValue, isNotEmpty, isNotNull, isNull } from '../empty.util';
import { FormService } from './form.service';
import { FormEntry, FormError } from './form.reducer';
-import { QUALDROP_GROUP_SUFFIX } from './builder/ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model';
-
-const QUALDROP_GROUP_REGEX = new RegExp(`${QUALDROP_GROUP_SUFFIX}_\\d+$`);
+import { DsDynamicLookupRelationModalComponent } from './builder/ds-dynamic-form-ui/relation-lookup-modal/dynamic-lookup-relation-modal.component';
+import { RelationshipOptions } from './builder/models/relationship-options.model';
+import { FormFieldMetadataValueObject } from './builder/models/form-field-metadata-value.model';
/**
* The default form component.
@@ -87,9 +89,9 @@ export class FormComponent implements OnDestroy, OnInit {
@Output() submitForm: EventEmitter> = new EventEmitter>();
/**
- * An object of FormGroup type
+ * Reference to NgbModal
*/
- // public formGroup: FormGroup;
+ modalRef: NgbModalRef;
/**
* Array to track all subscriptions and unsubscribe them onDestroy
@@ -99,7 +101,8 @@ export class FormComponent implements OnDestroy, OnInit {
constructor(private formService: FormService,
protected changeDetectorRef: ChangeDetectorRef,
- private formBuilderService: FormBuilderService) {
+ private formBuilderService: FormBuilderService,
+ private modalService: NgbModal) {
}
/**
@@ -311,6 +314,48 @@ export class FormComponent implements OnDestroy, OnInit {
this.formService.changeForm(this.formId, this.formModel);
}
+ isVirtual(arrayContext: DynamicFormArrayModel, index: number) {
+ const context = arrayContext.groups[index];
+ const value: FormFieldMetadataValueObject = (context.group[0] as any).metadataValue;
+ return isNotEmpty(value) && value.isVirtual;
+ }
+
+ hasRelationship(arrayContext: DynamicFormArrayModel, index: number) {
+ const context = arrayContext.groups[index];
+ const model = context.group[0] as any;
+ return isNotEmpty(model) && model.hasOwnProperty('relationship') && isNotEmpty(model.relationship);
+ }
+
+ /**
+ * Open a modal where the user can select relationships to be added to item being submitted
+ */
+ openLookup(arrayContext: DynamicFormArrayModel, index: number) {
+ const context = arrayContext.groups[index];
+ const model = context.group[0] as any;
+ this.modalRef = this.modalService.open(DsDynamicLookupRelationModalComponent, {
+ size: 'lg'
+ });
+ const modalComp = this.modalRef.componentInstance;
+
+ if (hasValue(model.value) && !model.readOnly) {
+ if (typeof model.value === 'string') {
+ modalComp.query = model.value;
+ } else if (typeof model.value.value === 'string') {
+ modalComp.query = model.value.value;
+ }
+ }
+
+ const config = model.relationshipConfig || model.relationship;
+ const relationshipOptions = Object.assign(new RelationshipOptions(), config);
+
+ modalComp.repeatable = model.repeatable;
+ modalComp.listId = `list-${model.submissionId}-${relationshipOptions.relationshipType}`;
+ modalComp.relationshipOptions = model.relationship;
+ modalComp.label = model.relationship.relationshipType;
+ modalComp.metadataFields = model.metadataFields;
+ modalComp.submissionId = model.submissionId;
+ }
+
protected getEvent($event: any, arrayContext: DynamicFormArrayModel, index: number, type: string): DynamicFormControlEvent {
const context = arrayContext.groups[index];
const itemGroupModel = context.context;
diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5
index 05d3aa4e49..ade2719e47 100644
--- a/src/assets/i18n/en.json5
+++ b/src/assets/i18n/en.json5
@@ -1257,7 +1257,7 @@
- "form.add": "Add",
+ "form.add": "Add more",
"form.add-help": "Click here to add the current entry and to add another one",