[TLC-1202] Centralise getTypeBindRelations to single static method

This commit is contained in:
Kim Shepherd
2025-09-18 15:05:15 +02:00
parent c47d988bca
commit 9244c24d11
3 changed files with 50 additions and 98 deletions

View File

@@ -9,12 +9,9 @@ import {
} from '@angular/forms'; } from '@angular/forms';
import { import {
DISABLED_MATCHER_PROVIDER, DISABLED_MATCHER_PROVIDER,
DynamicFormControlRelation,
DynamicFormRelationService, DynamicFormRelationService,
HIDDEN_MATCHER, HIDDEN_MATCHER,
HIDDEN_MATCHER_PROVIDER, HIDDEN_MATCHER_PROVIDER,
MATCH_VISIBLE,
OR_OPERATOR,
REQUIRED_MATCHER_PROVIDER, REQUIRED_MATCHER_PROVIDER,
} from '@ng-dynamic-forms/core'; } from '@ng-dynamic-forms/core';
@@ -85,7 +82,7 @@ describe('DSDynamicTypeBindRelationService test suite', () => {
}); });
it('Should get 1 related form models for mock relation model data', () => { it('Should get 1 related form models for mock relation model data', () => {
const testModel = mockInputWithTypeBindModel; const testModel = mockInputWithTypeBindModel;
testModel.typeBindRelations = getTypeBindRelations(['boundType']); testModel.typeBindRelations = DsDynamicTypeBindRelationService.getTypeBindRelations(['boundType'], 'dc.type');
const relatedModels = service.getRelatedFormModel(testModel); const relatedModels = service.getRelatedFormModel(testModel);
expect(relatedModels).toHaveSize(1); expect(relatedModels).toHaveSize(1);
}); });
@@ -94,7 +91,7 @@ describe('DSDynamicTypeBindRelationService test suite', () => {
describe('Test matchesCondition method', () => { describe('Test matchesCondition method', () => {
it('Should receive one subscription to dc.type type binding"', () => { it('Should receive one subscription to dc.type type binding"', () => {
const testModel = mockInputWithTypeBindModel; const testModel = mockInputWithTypeBindModel;
testModel.typeBindRelations = getTypeBindRelations(['boundType']); testModel.typeBindRelations = DsDynamicTypeBindRelationService.getTypeBindRelations(['boundType'], 'dc.type');
const dcTypeControl = new UntypedFormControl(); const dcTypeControl = new UntypedFormControl();
dcTypeControl.setValue('boundType'); dcTypeControl.setValue('boundType');
let subscriptions = service.subscribeRelations(testModel, dcTypeControl); let subscriptions = service.subscribeRelations(testModel, dcTypeControl);
@@ -103,7 +100,7 @@ describe('DSDynamicTypeBindRelationService test suite', () => {
it('Expect hasMatch to be true (ie. this should be hidden)', () => { it('Expect hasMatch to be true (ie. this should be hidden)', () => {
const testModel = mockInputWithTypeBindModel; const testModel = mockInputWithTypeBindModel;
testModel.typeBindRelations = getTypeBindRelations(['boundType']); testModel.typeBindRelations = DsDynamicTypeBindRelationService.getTypeBindRelations(['boundType'], 'dc.type');
const dcTypeControl = new UntypedFormControl(); const dcTypeControl = new UntypedFormControl();
dcTypeControl.setValue('boundType'); dcTypeControl.setValue('boundType');
testModel.typeBindRelations[0].when[0].value = 'anotherType'; testModel.typeBindRelations[0].when[0].value = 'anotherType';
@@ -118,7 +115,7 @@ describe('DSDynamicTypeBindRelationService test suite', () => {
it('Expect hasMatch to be false (ie. this should NOT be hidden)', () => { it('Expect hasMatch to be false (ie. this should NOT be hidden)', () => {
const testModel = mockInputWithTypeBindModel; const testModel = mockInputWithTypeBindModel;
testModel.typeBindRelations = getTypeBindRelations(['boundType']); testModel.typeBindRelations = DsDynamicTypeBindRelationService.getTypeBindRelations(['boundType'], 'dc.type');
const dcTypeControl = new UntypedFormControl(); const dcTypeControl = new UntypedFormControl();
dcTypeControl.setValue('boundType'); dcTypeControl.setValue('boundType');
testModel.typeBindRelations[0].when[0].value = 'boundType'; testModel.typeBindRelations[0].when[0].value = 'boundType';
@@ -134,18 +131,3 @@ describe('DSDynamicTypeBindRelationService test suite', () => {
}); });
}); });
function getTypeBindRelations(configuredTypeBindValues: string[]): DynamicFormControlRelation[] {
const bindValues = [];
configuredTypeBindValues.forEach((value) => {
bindValues.push({
id: 'dc.type',
value: value,
});
});
return [{
match: MATCH_VISIBLE,
operator: OR_OPERATOR,
when: bindValues,
}];
}

View File

@@ -13,7 +13,6 @@ import {
DynamicFormControlModel, DynamicFormControlModel,
DynamicFormControlRelation, DynamicFormControlRelation,
DynamicFormRelationService, DynamicFormRelationService,
MATCH_DISABLED,
MATCH_ENABLED, MATCH_ENABLED,
MATCH_VISIBLE, MATCH_VISIBLE,
OR_OPERATOR, OR_OPERATOR,
@@ -36,6 +35,48 @@ import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP } from './ds-dynamic-form-cons
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class DsDynamicTypeBindRelationService { export class DsDynamicTypeBindRelationService {
/**
* Get the type bind values from the REST data for a specific field
* The return value is any[] in the method signature but in reality it's
* returning the 'relation' that'll be used for a dynamic matcher when filtering
* fields in type bind, made up of a 'match' outcome (make this field visible), an 'operator'
* (OR) and a 'when' condition (the bindValues array).
* @param configuredTypeBindValues array of types from the submission definition (CONFIG_DATA)
* @param typeField
* @private
* @return DynamicFormControlRelation[] array with one relation in it, for type bind matching to show a field
*/
public static getTypeBindRelations(configuredTypeBindValues: string[], typeField: string): DynamicFormControlRelation[] {
const bindValues = [];
configuredTypeBindValues.forEach((value) => {
bindValues.push({
id: typeField,
value: value,
});
});
// match: MATCH_VISIBLE means that if true, the field / component will be visible
// operator: OR means that all the values in the 'when' condition will be compared with OR, not AND
// when: the list of values to match against, in this case the list of strings from <type-bind>...</type-bind>
// Example: Field [x] will be VISIBLE if item type = book OR item type = book_part
//
// The opposing match value will be the dc.type for the workspace item
//
// MATCH_ENABLED is now also returned, so that hidden type-bound fields that are 'required'
// do not trigger false validation errors
return [
{
match: MATCH_ENABLED,
operator: OR_OPERATOR,
when: bindValues,
},
{
match: MATCH_VISIBLE,
operator: OR_OPERATOR,
when: bindValues,
},
];
}
constructor(@Optional() @Inject(DYNAMIC_MATCHERS) private dynamicMatchers: DynamicFormControlMatcher[], constructor(@Optional() @Inject(DYNAMIC_MATCHERS) private dynamicMatchers: DynamicFormControlMatcher[],
protected dynamicFormRelationService: DynamicFormRelationService, protected dynamicFormRelationService: DynamicFormRelationService,
protected formBuilderService: FormBuilderService, protected formBuilderService: FormBuilderService,
@@ -218,30 +259,4 @@ export class DsDynamicTypeBindRelationService {
return subscriptions; return subscriptions;
} }
/**
* Helper function to construct a typeBindRelations array
* @param configuredTypeBindValues
*/
public getTypeBindRelations(configuredTypeBindValues: string[]): DynamicFormControlRelation[] {
const bindValues = [];
configuredTypeBindValues.forEach((value) => {
bindValues.push({
id: 'dc.type',
value: value,
});
});
return [
{
match: MATCH_ENABLED,
operator: OR_OPERATOR,
when: bindValues,
},
{
match: MATCH_VISIBLE,
operator: OR_OPERATOR,
when: bindValues,
},
];
}
} }

View File

@@ -2,14 +2,7 @@ import {
Inject, Inject,
InjectionToken, InjectionToken,
} from '@angular/core'; } from '@angular/core';
import { import { DynamicFormControlLayout } from '@ng-dynamic-forms/core';
DynamicFormControlLayout,
DynamicFormControlRelation,
MATCH_DISABLED,
MATCH_ENABLED,
MATCH_VISIBLE,
OR_OPERATOR,
} from '@ng-dynamic-forms/core';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import uniqueId from 'lodash/uniqueId'; import uniqueId from 'lodash/uniqueId';
@@ -22,6 +15,7 @@ import {
isNotNull, isNotNull,
isNotUndefined, isNotUndefined,
} from '../../../empty.util'; } from '../../../empty.util';
import { DsDynamicTypeBindRelationService } from '../ds-dynamic-form-ui/ds-dynamic-type-bind-relation.service';
import { import {
DsDynamicInputModel, DsDynamicInputModel,
DsDynamicInputModelConfig, DsDynamicInputModelConfig,
@@ -100,7 +94,7 @@ export abstract class FieldParser {
metadataFields: this.getAllFieldIds(), metadataFields: this.getAllFieldIds(),
hasSelectableMetadata: isNotEmpty(this.configData.selectableMetadata), hasSelectableMetadata: isNotEmpty(this.configData.selectableMetadata),
isDraggable, isDraggable,
typeBindRelations: isNotEmpty(this.configData.typeBind) ? this.getTypeBindRelations(this.configData.typeBind, typeBindRelations: isNotEmpty(this.configData.typeBind) ? DsDynamicTypeBindRelationService.getTypeBindRelations(this.configData.typeBind,
this.parserOptions.typeField) : null, this.parserOptions.typeField) : null,
groupFactory: () => { groupFactory: () => {
let model; let model;
@@ -329,7 +323,7 @@ export abstract class FieldParser {
// If typeBind is configured // If typeBind is configured
if (isNotEmpty(this.configData.typeBind)) { if (isNotEmpty(this.configData.typeBind)) {
(controlModel as DsDynamicInputModel).typeBindRelations = this.getTypeBindRelations(this.configData.typeBind, (controlModel as DsDynamicInputModel).typeBindRelations = DsDynamicTypeBindRelationService.getTypeBindRelations(this.configData.typeBind,
this.parserOptions.typeField); this.parserOptions.typeField);
} }
@@ -358,45 +352,6 @@ export abstract class FieldParser {
); );
} }
/**
* Get the type bind values from the REST data for a specific field
* The return value is any[] in the method signature but in reality it's
* returning the 'relation' that'll be used for a dynamic matcher when filtering
* fields in type bind, made up of a 'match' outcome (make this field visible), an 'operator'
* (OR) and a 'when' condition (the bindValues array).
* @param configuredTypeBindValues array of types from the submission definition (CONFIG_DATA)
* @param typeField
* @private
* @return DynamicFormControlRelation[] array with one relation in it, for type bind matching to show a field
*/
private getTypeBindRelations(configuredTypeBindValues: string[], typeField: string): DynamicFormControlRelation[] {
const bindValues = [];
configuredTypeBindValues.forEach((value) => {
bindValues.push({
id: typeField,
value: value,
});
});
// match: MATCH_VISIBLE means that if true, the field / component will be visible
// operator: OR means that all the values in the 'when' condition will be compared with OR, not AND
// when: the list of values to match against, in this case the list of strings from <type-bind>...</type-bind>
// Example: Field [x] will be VISIBLE if item type = book OR item type = book_part
//
// The opposing match value will be the dc.type for the workspace item
return [
{
match: MATCH_ENABLED,
operator: OR_OPERATOR,
when: bindValues,
},
{
match: MATCH_VISIBLE,
operator: OR_OPERATOR,
when: bindValues,
},
];
}
protected hasRegex() { protected hasRegex() {
return hasValue(this.configData.input.regex); return hasValue(this.configData.input.regex);
} }