create-claude-workspace 1.1.69 → 1.1.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -148,6 +148,53 @@ export class ProjectDetail {
|
|
|
148
148
|
- WebSocket/SSE streams — use dedicated services
|
|
149
149
|
- Non-HTTP async — use `resource()` instead
|
|
150
150
|
|
|
151
|
+
## Forms — Signal Forms API
|
|
152
|
+
|
|
153
|
+
Use the **signal-based forms API** (`@angular/forms/signals`) for all form handling when available in the project's Angular version (stable or experimental). NEVER use legacy `FormControl`/`FormGroup`/`FormBuilder`/`ReactiveFormsModule`.
|
|
154
|
+
|
|
155
|
+
**Signal forms pattern:**
|
|
156
|
+
```typescript
|
|
157
|
+
import { Component, signal } from '@angular/core';
|
|
158
|
+
import { form, FormField, required, email, minLength } from '@angular/forms/signals';
|
|
159
|
+
|
|
160
|
+
@Component({
|
|
161
|
+
imports: [FormField],
|
|
162
|
+
template: `
|
|
163
|
+
<input type="email" [formField]="loginForm.email" />
|
|
164
|
+
<input type="password" [formField]="loginForm.password" />
|
|
165
|
+
<button [disabled]="loginForm.invalid()">Submit</button>
|
|
166
|
+
`,
|
|
167
|
+
})
|
|
168
|
+
export class LoginForm {
|
|
169
|
+
readonly loginModel = signal({ email: '', password: '' });
|
|
170
|
+
readonly loginForm = form(this.loginModel, (schema) => {
|
|
171
|
+
required(schema.email);
|
|
172
|
+
email(schema.email);
|
|
173
|
+
required(schema.password);
|
|
174
|
+
minLength(schema.password, 8);
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// Field state is signal-based:
|
|
178
|
+
// this.loginForm.email().value() — current value (signal)
|
|
179
|
+
// this.loginForm.email().dirty() — boolean signal
|
|
180
|
+
// this.loginForm.email().invalid() — boolean signal
|
|
181
|
+
// this.loginForm.email().value.set('new@email.com') — update programmatically
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Key rules:**
|
|
186
|
+
- `form()` function with a signal model — form structure derived from model shape
|
|
187
|
+
- Validators from `@angular/forms/signals`: `required()`, `email()`, `minLength()`, `maxLength()`, `min()`, `max()`, `pattern()`
|
|
188
|
+
- Template binding via `[formField]` directive (import `FormField`)
|
|
189
|
+
- All field state (value, dirty, invalid, disabled) is signal-based — bind directly in templates
|
|
190
|
+
- No `.valueChanges` subscriptions — state is already reactive
|
|
191
|
+
|
|
192
|
+
**NEVER:**
|
|
193
|
+
- `new FormControl()` / `new FormGroup()` / `new FormArray()` / `FormBuilder` — use `form()` with signal model
|
|
194
|
+
- `ReactiveFormsModule` / `FormsModule` — use `FormField` directive from `@angular/forms/signals`
|
|
195
|
+
- `.valueChanges.subscribe()` — field state is already reactive via signals
|
|
196
|
+
- Wrapping validators in arrow functions (`control => Validators.required(control)`)
|
|
197
|
+
|
|
151
198
|
## Templates — MINIMAL Logic
|
|
152
199
|
|
|
153
200
|
- ZERO method calls in templates — wrap in `computed()`, bind the signal
|
|
@@ -343,6 +390,7 @@ describe('CardBadge', () => {
|
|
|
343
390
|
|
|
344
391
|
When reviewing Angular code, check:
|
|
345
392
|
- Signal usage: signal/computed/input/output/model correctly used
|
|
393
|
+
- Forms: SignalFormBuilder used (no legacy FormControl/FormGroup/FormBuilder)
|
|
346
394
|
- ZERO method calls in templates — all derived state in computed()
|
|
347
395
|
- Feature vs dumb separation — no inject() in ui/ components
|
|
348
396
|
- Content projection (composite pattern) over deep @Input trees
|