Angular Reactive Forms patterns with strict typing for FormControl bindings in templates. Trigger: When creating Angular forms, fixing FormControl type errors, or binding form controls in templates.
AbstractControl | null template binding errors.[formControl] and formControlName.app-input and app-toggle.Before using shared controls, check their READMEs under apps/frontend/src/app/shared/components/{input,toggle}/ and verify current inputs in the component source.
apps/frontend/src/app/private/modules/store/settings/general/components/general-settings-form/FormGroup examples: apps/frontend/src/app/private/modules/super-admin/subscriptions/pages/gateway/ and plans/plan-form.component.tsformControlName example: apps/frontend/src/app/private/modules/store/products/pages/product-create-page/apps/frontend/src/app/shared/components/input/input.component.ts and toggle/toggle.component.ts| Template Pattern | Use When | Rule |
| --- | --- | --- |
| formControlName="name" inside [formGroup] | Standard form layout with static control names | Preferred for straightforward forms |
| [formControl]="nameControl" | Passing a specific control to a component or dynamic binding | Use a typed getter or typed property |
| [control]="..." | Component-specific extra input, not Angular Forms binding | Avoid form.get() directly unless the component explicitly needs AbstractControl |
Do not use $any(form.get(...)) in new code. It exists in legacy pages only.
Use typed getters when binding to [formControl].
readonly form = new FormGroup({
name: new FormControl('', { nonNullable: true }),
enabled: new FormControl(false, { nonNullable: true }),
logoUrl: new FormControl<string | null>(null),
});
get nameControl(): FormControl<string> {
return this.form.get('name') as FormControl<string>;
}
get enabledControl(): FormControl<boolean> {
return this.form.get('enabled') as FormControl<boolean>;
}
get logoUrlControl(): FormControl<string | null> {
return this.form.get('logoUrl') as FormControl<string | null>;
}
<app-input [formControl]="nameControl" label="Name" />
<app-toggle [formControl]="enabledControl" label="Enabled" />
Use formControlName when the control is inside the current [formGroup] and no explicit control reference is needed.
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<app-input formControlName="name" label="Name" />
<app-toggle formControlName="is_active" label="Active" />
</form>
This avoids repetitive getters for large static forms.
Prefer typed forms for new complex forms.
interface GatewayFormControls {
public_key: FormControl<string>;
private_key: FormControl<string>;
enabled: FormControl<boolean>;
}
readonly form = new FormGroup<GatewayFormControls>({
public_key: new FormControl('', { nonNullable: true }),
private_key: new FormControl('', { nonNullable: true }),
enabled: new FormControl(false, { nonNullable: true }),
});
InputComponent is a CVA and supports text-like types including text, email, password, number, tel, url, search, date, time, datetime-local, and color.
Important InputComponent features:
currency, currencyDecimals, and allowNegative for money inputs.prefixIcon, suffixIcon, suffixClickable, and suffixClick.tooltipText, tooltipPosition, and tooltipVisible.ToggleComponent is a CVA with checked, disabled, label, ariaLabel, and styleVariant. It emits both toggled and changed, and stores form-written state in signals.
In any custom CVA, every field written by writeValue or setDisabledState and read by the template must be a signal().
readonly value = signal(false);
readonly disabledFromForm = signal(false);
writeValue(value: boolean): void {
this.value.set(Boolean(value));
}
setDisabledState(disabled: boolean): void {
this.disabledFromForm.set(disabled);
}
Plain mutable fields in CVA callbacks can leave the template stale in Zoneless mode.
[formControl]="form.get('name')" in templates.[formControl]="form.get('name')!"; use a typed getter.$any(...) in new form templates.any.value, disabled, checked, or selected state.vendix-zoneless-signals - Signals, CVA, and change detection rulesvendix-currency-formatting - Money input/display patternsvendix-date-timezone - Date input and date-only handlingvendix-frontend-sticky-header - Form page headers and save/cancel actionsnpx skills add Rzyfront/vendix-angular-forms下载完整 Skill 目录,包含 SKILL.md 及所有相关文件
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer