Skip to content

Commit 21eaaba

Browse files
committed
angular-material: Translate enum for AutocompleteControlRenderer
1 parent e642b3d commit 21eaaba

File tree

2 files changed

+96
-17
lines changed

2 files changed

+96
-17
lines changed

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';
@@ -92,9 +97,9 @@ import { MatAutocompleteModule } from '@angular/material/autocomplete';
9297
>
9398
<mat-option
9499
*ngFor="let option of filteredOptions | async"
95-
[value]="option"
100+
[value]="option.value"
96101
>
97-
{{ option }}
102+
{{ option.label }}
98103
</mat-option>
99104
</mat-autocomplete>
100105
<mat-hint *ngIf="shouldShowUnfocusedDescription() || focused">{{
@@ -127,14 +132,22 @@ export class AutocompleteControlRenderer
127132
extends JsonFormsControl
128133
implements OnInit
129134
{
130-
@Input() options: string[];
131-
filteredOptions: Observable<string[]>;
135+
@Input() options?: EnumOption[] | string[];
136+
translatedOptions?: EnumOption[];
137+
filteredOptions: Observable<EnumOption[]>;
132138
shouldFilter: boolean;
133139
focused = false;
134140

135141
constructor(jsonformsService: JsonFormsAngularService) {
136142
super(jsonformsService);
137143
}
144+
145+
protected mapToProps(
146+
state: JsonFormsState
147+
): StatePropsOfControl & OwnPropsOfEnum {
148+
return mapStateToEnumControlProps(state, this.getOwnProps());
149+
}
150+
138151
getEventValue = (event: any) => event.target.value;
139152

140153
ngOnInit() {
@@ -146,6 +159,10 @@ export class AutocompleteControlRenderer
146159
);
147160
}
148161

162+
mapAdditionalProps(_props: StatePropsOfControl & OwnPropsOfEnum) {
163+
this.translatedOptions = _props.options;
164+
}
165+
149166
updateFilter(event: any) {
150167
// ENTER
151168
if (event.keyCode === 13) {
@@ -158,30 +175,45 @@ export class AutocompleteControlRenderer
158175
onSelect(ev: MatAutocompleteSelectedEvent) {
159176
const path = composeWithUi(this.uischema as ControlElement, this.path);
160177
this.shouldFilter = false;
161-
this.jsonFormsService.updateCore(
162-
Actions.update(path, () => ev.option.value)
163-
);
178+
const option: EnumOption = ev.option.value;
179+
this.jsonFormsService.updateCore(Actions.update(path, () => option.value));
164180
this.triggerValidation();
165181
}
166182

167-
filter(val: string): string[] {
168-
return (this.options || this.scopedSchema.enum || []).filter(
183+
filter(val: string): EnumOption[] {
184+
return (this.translatedOptions || []).filter(
169185
(option) =>
170186
!this.shouldFilter ||
171187
!val ||
172-
option.toLowerCase().indexOf(val.toLowerCase()) === 0
188+
option.label.toLowerCase().indexOf(val.toLowerCase()) === 0
173189
);
174190
}
175-
protected getOwnProps(): OwnPropsOfAutoComplete {
191+
protected getOwnProps(): OwnPropsOfControl & OwnPropsOfEnum {
176192
return {
177193
...super.getOwnProps(),
178-
options: this.options,
194+
options: this.stringOptionsToEnumOptions(this.options),
179195
};
180196
}
181-
}
182197

183-
export const enumControlTester: RankedTester = rankWith(2, isEnumControl);
198+
/**
199+
* For {@link options} input backwards compatibility
200+
*/
201+
protected stringOptionsToEnumOptions(
202+
options: typeof this.options
203+
): EnumOption[] | undefined {
204+
if (!options) {
205+
return undefined;
206+
}
184207

185-
interface OwnPropsOfAutoComplete extends OwnPropsOfControl {
186-
options: string[];
208+
return options.every((item) => typeof item === 'string')
209+
? options.map((str) => {
210+
return {
211+
label: str,
212+
value: str,
213+
} satisfies EnumOption;
214+
})
215+
: options;
216+
}
187217
}
218+
219+
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)