Skip to content

Commit 4d5741f

Browse files
Port #1336 to dtq-dev-9-base: UFAL/fix(submission): keep dc.type dropdown display after change (ufal#157) (#1336) (#1504)
The "type of resource" scrollable dropdown blanked out after its value changed when the backend was slow: the reloaded model value came back with a populated value/authority but an empty display, and setCurrentValue rendered that empty display verbatim. Both branches of setCurrentValue now fall back to the underlying value when display is empty, which is the convention inputFormatter (r.181) already follows. Spec: 8 it() -> 11. One covers the valueChanges path, one the init path, and one is the actual regression for ufal/clarin-dspace#1377 — it pushes a value with an empty display through group.valueChanges, the real reload entry point, and asserts the rendered input still reads "Corpus". The init test stubs getInitValueFromModel rather than relying on isNotEmpty(new VocabularyEntry()), and builds its value with Object.assign around an empty FormFieldMetadataValueObject, because that constructor would otherwise apply its own `display || value` and hide the very case under test. Negative control run on this branch: with the two component lines reverted and the new specs in place, karma reports "TOTAL: 3 FAILED, 8 SUCCESS" and names exactly the three new tests; with the fix, "TOTAL: 11 SUCCESS". The specs fail for the right reason. v9 notes: this is NOT a clean cherry-pick, despite the change being two lines. `git cherry-pick -x 41ead07` conflicts in BOTH files — the 9-base component has the vanilla trailing comma after the `map(...)` argument and uses `of` where the fork uses `of as observableOf`, so neither line matches. The hunks were applied by hand; the result differs from the source only by those two adaptations. In the spec, `observableOf` becomes `of` and the FormFieldMetadataValueObject import is placed where simple-import-sort wants it on this branch (after the ../../../../../testing/ block). Card FE-19 (tranche T3). Source: 41ead07 (dtq-dev PR #1336) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 1e195a4 commit 4d5741f

2 files changed

Lines changed: 48 additions & 2 deletions

File tree

src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.spec.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
} from '@ng-dynamic-forms/core';
2929
import { TranslateModule } from '@ngx-translate/core';
3030
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
31+
import { of } from 'rxjs';
3132

3233
import { APP_DATA_SERVICES_MAP } from '../../../../../../../config/app-config.interface';
3334
import { VocabularyEntry } from '../../../../../../core/submission/vocabularies/models/vocabulary-entry.model';
@@ -42,6 +43,7 @@ import {
4243
hasClass,
4344
} from '../../../../../testing/utils.test';
4445
import { VocabularyServiceStub } from '../../../../../testing/vocabulary-service.stub';
46+
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
4547
import { DsDynamicScrollableDropdownComponent } from './dynamic-scrollable-dropdown.component';
4648
import { DynamicScrollableDropdownModel } from './dynamic-scrollable-dropdown.model';
4749

@@ -232,6 +234,50 @@ describe('Dynamic Dynamic Scrollable Dropdown component', () => {
232234
expect(scrollableDropdownComp.optionsList).toEqual(vocabularyServiceStub.getList());
233235
expect(scrollableDropdownComp.model.value).toEqual(modelValue);
234236
});
237+
238+
it('should fall back to the underlying value when display is empty on value change', () => {
239+
const valueWithEmptyDisplay = { display: '', value: 'Corpus' };
240+
scrollableDropdownComp.setCurrentValue(valueWithEmptyDisplay);
241+
242+
let currentValue;
243+
scrollableDropdownComp.currentValue.subscribe((v) => currentValue = v);
244+
245+
expect(currentValue).toBe('Corpus');
246+
});
247+
248+
it('should fall back to the underlying value when display is empty on init', () => {
249+
// Build the value bypassing the FormFieldMetadataValueObject constructor (which would
250+
// otherwise apply its own `display || value`), so the init branch genuinely receives an
251+
// empty display and exercises the fallback in setCurrentValue.
252+
const emptyDisplayValue = Object.assign(
253+
new FormFieldMetadataValueObject(),
254+
{ display: '', value: 'Corpus' },
255+
);
256+
spyOn(scrollableDropdownComp, 'getInitValueFromModel').and.returnValue(of(emptyDisplayValue));
257+
scrollableDropdownComp.setCurrentValue(emptyDisplayValue, true);
258+
259+
let currentValue;
260+
scrollableDropdownComp.currentValue.subscribe((v) => currentValue = v);
261+
262+
expect(currentValue).toBe('Corpus');
263+
});
264+
265+
// Regression for ufal/clarin-dspace#1377: after a dc.type change the section
266+
// reloads and pushes a new value with an empty display through the form control.
267+
// The rendered input must not blank out.
268+
it('should keep the rendered value when a value with empty display arrives via valueChanges', fakeAsync(() => {
269+
const reloadedValue = Object.assign(
270+
new FormFieldMetadataValueObject(),
271+
{ display: '', value: 'Corpus', authority: 'corpus-auth' },
272+
);
273+
274+
scrollableDropdownComp.group.get(scrollableDropdownComp.model.id).setValue(reloadedValue);
275+
tick();
276+
scrollableDropdownFixture.detectChanges();
277+
278+
const input = scrollableDropdownFixture.debugElement.query(By.css('input.form-control')).nativeElement;
279+
expect(input.value).toBe('Corpus');
280+
}));
235281
});
236282
});
237283
});

src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom
360360

361361
if (init && !this.useFindAllService) {
362362
result = this.getInitValueFromModel().pipe(
363-
map((formValue: FormFieldMetadataValueObject) => formValue.display),
363+
map((formValue: FormFieldMetadataValueObject) => formValue.display || formValue.value),
364364
);
365365
} else {
366366
if (isEmpty(value)) {
@@ -370,7 +370,7 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom
370370
} else if (this.useFindAllService) {
371371
result = of(value[this.model.displayKey]);
372372
} else {
373-
result = of(value.display);
373+
result = of(value.display || value.value);
374374
}
375375
}
376376

0 commit comments

Comments
 (0)