Skip to content

Commit a7d33df

Browse files
committed
angular-material: Translate enum for AutocompleteControlRenderer
1 parent d1d2c86 commit a7d33df

2 files changed

Lines changed: 96 additions & 17 deletions

File tree

packages/angular-material/src/library/controls/autocomplete.renderer.ts

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,15 @@ import {
3434
Actions,
3535
composeWithUi,
3636
ControlElement,
37+
EnumOption,
3738
isEnumControl,
39+
JsonFormsState,
40+
mapStateToEnumControlProps,
3841
OwnPropsOfControl,
42+
OwnPropsOfEnum,
3943
RankedTester,
4044
rankWith,
45+
StatePropsOfControl,
4146
} from '@jsonforms/core';
4247
import type { Observable } from 'rxjs';
4348
import { map, startWith } from 'rxjs/operators';
@@ -70,9 +75,9 @@ import { MatAutocompleteModule } from '@angular/material/autocomplete';
7075
>
7176
<mat-option
7277
*ngFor="let option of filteredOptions | async"
73-
[value]="option"
78+
[value]="option.value"
7479
>
75-
{{ option }}
80+
{{ option.label }}
7681
</mat-option>
7782
</mat-autocomplete>
7883
<mat-hint *ngIf="shouldShowUnfocusedDescription() || focused">{{
@@ -105,14 +110,22 @@ export class AutocompleteControlRenderer
105110
extends JsonFormsControl
106111
implements OnInit
107112
{
108-
@Input() options: string[];
109-
filteredOptions: Observable<string[]>;
113+
@Input() options?: EnumOption[] | string[];
114+
translatedOptions?: EnumOption[];
115+
filteredOptions: Observable<EnumOption[]>;
110116
shouldFilter: boolean;
111117
focused = false;
112118

113119
constructor(jsonformsService: JsonFormsAngularService) {
114120
super(jsonformsService);
115121
}
122+
123+
protected mapToProps(
124+
state: JsonFormsState
125+
): StatePropsOfControl & OwnPropsOfEnum {
126+
return mapStateToEnumControlProps(state, this.getOwnProps());
127+
}
128+
116129
getEventValue = (event: any) => event.target.value;
117130

118131
ngOnInit() {
@@ -124,6 +137,10 @@ export class AutocompleteControlRenderer
124137
);
125138
}
126139

140+
mapAdditionalProps(_props: StatePropsOfControl & OwnPropsOfEnum) {
141+
this.translatedOptions = _props.options;
142+
}
143+
127144
updateFilter(event: any) {
128145
// ENTER
129146
if (event.keyCode === 13) {
@@ -136,30 +153,45 @@ export class AutocompleteControlRenderer
136153
onSelect(ev: MatAutocompleteSelectedEvent) {
137154
const path = composeWithUi(this.uischema as ControlElement, this.path);
138155
this.shouldFilter = false;
139-
this.jsonFormsService.updateCore(
140-
Actions.update(path, () => ev.option.value)
141-
);
156+
const option: EnumOption = ev.option.value;
157+
this.jsonFormsService.updateCore(Actions.update(path, () => option.value));
142158
this.triggerValidation();
143159
}
144160

145-
filter(val: string): string[] {
146-
return (this.options || this.scopedSchema.enum || []).filter(
161+
filter(val: string): EnumOption[] {
162+
return (this.translatedOptions || []).filter(
147163
(option) =>
148164
!this.shouldFilter ||
149165
!val ||
150-
option.toLowerCase().indexOf(val.toLowerCase()) === 0
166+
option.label.toLowerCase().indexOf(val.toLowerCase()) === 0
151167
);
152168
}
153-
protected getOwnProps(): OwnPropsOfAutoComplete {
169+
protected getOwnProps(): OwnPropsOfControl & OwnPropsOfEnum {
154170
return {
155171
...super.getOwnProps(),
156-
options: this.options,
172+
options: this.stringOptionsToEnumOptions(this.options),
157173
};
158174
}
159-
}
160175

161-
export const enumControlTester: RankedTester = rankWith(2, isEnumControl);
176+
/**
177+
* For {@link options} input backwards compatibility
178+
*/
179+
protected stringOptionsToEnumOptions(
180+
options: typeof this.options
181+
): EnumOption[] | undefined {
182+
if (!options) {
183+
return undefined;
184+
}
162185

163-
interface OwnPropsOfAutoComplete extends OwnPropsOfControl {
164-
options: string[];
186+
return options.every((item) => typeof item === 'string')
187+
? options.map((str) => {
188+
return {
189+
label: str,
190+
value: str,
191+
} satisfies EnumOption;
192+
})
193+
: options;
194+
}
165195
}
196+
197+
export const enumControlTester: RankedTester = rankWith(2, isEnumControl);

packages/angular-material/test/autocomplete-control.spec.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@ import {
4444
setupMockStore,
4545
getJsonFormsService,
4646
} from './common';
47-
import { ControlElement, JsonSchema, Actions } from '@jsonforms/core';
47+
import {
48+
ControlElement,
49+
JsonSchema,
50+
Actions,
51+
JsonFormsCore,
52+
} from '@jsonforms/core';
4853
import { AutocompleteControlRenderer } from '../src';
4954
import { JsonFormsAngularService } from '@jsonforms/angular';
5055
import { ErrorObject } from 'ajv';
@@ -275,6 +280,48 @@ describe('AutoComplete control Input Event Tests', () => {
275280
.args[0] as MatAutocompleteSelectedEvent;
276281
expect(event.option.value).toBe('Y');
277282
}));
283+
it('should render translated enum correctly', fakeAsync(async () => {
284+
setupMockStore(fixture, { uischema, schema, data });
285+
const state: JsonFormsCore = {
286+
data,
287+
schema,
288+
uischema,
289+
};
290+
getJsonFormsService(component).init({
291+
core: state,
292+
i18n: {
293+
translate: (key, defaultMessage) => {
294+
const translations: { [key: string]: string } = {
295+
'foo.A': 'Translated A',
296+
'foo.B': 'Translated B',
297+
'foo.C': 'Translated C',
298+
};
299+
return translations[key] ?? defaultMessage;
300+
},
301+
},
302+
});
303+
getJsonFormsService(component).updateCore(
304+
Actions.init(data, schema, uischema)
305+
);
306+
component.ngOnInit();
307+
fixture.detectChanges();
308+
const spy = spyOn(component, 'onSelect');
309+
310+
await (await loader.getHarness(MatAutocompleteHarness)).focus();
311+
fixture.detectChanges();
312+
313+
await (
314+
await loader.getHarness(MatAutocompleteHarness)
315+
).selectOption({
316+
text: 'Translated B',
317+
});
318+
fixture.detectChanges();
319+
tick();
320+
321+
const event = spy.calls.mostRecent()
322+
.args[0] as MatAutocompleteSelectedEvent;
323+
expect(event.option.value).toBe('B');
324+
}));
278325
});
279326
describe('AutoComplete control Error Tests', () => {
280327
let fixture: ComponentFixture<AutocompleteControlRenderer>;

0 commit comments

Comments
 (0)