angular / angular/angular

Enable dynamic schema composition based on form state

Open
#67,071 4 comments 3 reactions 0 assignees View on GitHub
area: forms forms: signals
Dominant language
TypeScript
Stars
101k
Forks
27.5k
Avg merge
1d 19h
Merged PRs (30d)
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);
```

Contributor guide

Open the contributing guide

Research direction

Start by tracing the form, applyWhen, schema, and context.valueOf APIs to understand how schemas are currently constructed and when form context is available. Done means a schema can be built from runtime form context, with coverage for the activityType fieldConfig example and the existing behavior preserved.

Written by the indexing model from the issue text.

Assessment

Tech stack
angular, typescript
Domain
frontend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.