Enable dynamic schema composition based on form state
- Langage dominant
- TypeScript
- Étoiles
- 101k
- Forks
- 27.5k
- Merge moyen
- 1 j 19 h
- PR mergées (30 j)
- 288
Description
### Which @angular/* package(s) are relevant/related to the feature request?
_No response_
---
### Description
I have a form with different properties.
```ts
export interface Field {
fieldName: string;
fieldType?: string;
fieldRequired?: boolean;
fieldMaxSize?: number;
fieldVisible?: boolean;
}
export interface FieldConfig {
fields: Field[];
}
export interface Order {
label: string;
// ...
}
export interface ActivityType {
label: string;
fieldConfig: FieldConfig;
}
export function fieldConfigSchema(fieldConfig: FieldConfig) {
return schema(path => {
for (const field of fieldConfig.fields) {
required(path[field.fieldName], { when: () => field.fieldRequired });
hidden(path[field.fieldName], () => !field.fieldVisible);
maxLength(path[field.fieldName], () => field.fieldMaxSize);
}
});
}
export interface FormModel {
user: User;
activityType: ActivityType;
order: Order;
}
```
The form is defined as follows:
```ts
formModel = signal({
user: null,
activityType: null,
order: null
});
form = form(this.formModel, path => {
applyWhen(
path.order,
context => !!context.valueOf(path.activityType)?.fieldConfig,
fieldConfigSchema(
/* value of fieldConfig from activityType not available here */
)
);
});
```
The issue is that `fieldConfigSchema` needs access to the `fieldConfig`
coming from the selected `activityType`, but that value is only available
through the form context.
---
### Proposed solution
Allow building a schema dynamically based on the form context:
```ts
applyWhen(
path.order,
context => !!context.valueOf(path.activityType)?.fieldConfig,
context =>
fieldConfigSchema(
context.valueOf(path.activityType).fieldConfig
)
);
```
This would allow the schema to be constructed using runtime values from
the form context.
---
### Alternatives considered
```ts
export function fieldConfigSchema(fieldConfig: Signal) {
return schema(path => {
for (const field of fieldConfig().fields) {
required(path[field.fieldName], { when: () => field.fieldRequired });
hidden(path[field.fieldName], () => !field.fieldVisible);
maxLength(path[field.fieldName], () => field.fieldMaxSize);
}
});
}
form = form(this.formModel, path => {
applyWhen(
path.order,
context => !!context.valueOf(path.activityType)?.fieldConfig,
fieldConfigSchema(this.fieldConfig)
);
});
fieldConfig = computed(() => this.form.activityType().value()?.fieldConfig);
```
Guide de contribution
Ouvrir le guide de contribution
Piste de recherche
Commencez par suivre les API form, applyWhen, schema et context.valueOf afin de comprendre comment les schémas sont actuellement construits et quand le contexte de form est disponible. Le travail est terminé lorsqu’un schéma peut être construit à partir du contexte de form à l’exécution, avec une couverture pour l’exemple activityType fieldConfig et en préservant le comportement existant.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- angular, typescript
- Domaine
- frontend
- Type d'issue
- Fonctionnalité
- Difficulté
- 5/5
- Temps estimé
- Plus d'une semaine
- Activité
- Calme
- Clarté
- Plutôt claire
- Accessibilité débutants
- 35/100