Skip to content

Commit e8f08fd

Browse files
committed
translate: translations Signals with forms guide
Fixes #86
1 parent 5005132 commit e8f08fd

File tree

3 files changed

+363
-92
lines changed

3 files changed

+363
-92
lines changed

adev-es/src/app/routing/sub-navigation-data.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ const DOCS_SUB_NAVIGATION_DATA: NavigationItem[] = [
6666
contentPath: 'introduction/essentials/templates',
6767
},
6868
{
69-
label: 'Forms with signals',
69+
label: 'Formularios con signals',
7070
path: 'essentials/signal-forms',
7171
contentPath: 'introduction/essentials/signal-forms',
7272
status: 'new',
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
<docs-decorative-header title="Forms with signals" imgSrc="adev/src/assets/images/signals.svg"> </docs-decorative-header>
2+
3+
IMPORTANT: Signal Forms are [experimental](/reference/releases#experimental). The API may change in future releases. Avoid using experimental APIs in production applications without understanding the risks.
4+
5+
Signal Forms manage form state using Angular signals to provide automatic synchronization between your data model and the UI with Angular Signals.
6+
7+
This guide walks you through the core concepts to create forms with Signal Forms. Here's how it works:
8+
9+
## Creating your first form
10+
11+
### 1. Create a form model with `signal()`
12+
13+
Every form starts by creating a signal that holds your form's data model:
14+
15+
```ts
16+
interface LoginData {
17+
email: string;
18+
password: string;
19+
}
20+
21+
const loginModel = signal<LoginData>({
22+
email: '',
23+
password: '',
24+
});
25+
```
26+
27+
### 2. Pass the form model to `form()` to create a `FieldTree`
28+
29+
Then, you pass your form model into the `form()` function to create a **field tree** - an object structure that mirrors your model's shape, allowing you to access fields with dot notation:
30+
31+
```ts
32+
const loginForm = form(loginModel);
33+
34+
// Access fields directly by property name
35+
loginForm.email
36+
loginForm.password
37+
```
38+
39+
### 3. Bind HTML inputs with `[field]` directive
40+
41+
Next, you bind your HTML inputs to the form using the `[field]` directive, which creates two-way binding between them:
42+
43+
```html
44+
<input type="email" [field]="loginForm.email" />
45+
<input type="password" [field]="loginForm.password" />
46+
```
47+
48+
As a result, user changes (such as typing in the field) automatically updates the form.
49+
50+
NOTE: The `[field]` directive also syncs field state for attributes like `required`, `disabled`, and `readonly` when appropriate.
51+
52+
### 4. Read field values with `value()`
53+
54+
You can access field state by calling the field as a function. This returns a `FieldState` object containing reactive signals for the field's value, validation status, and interaction state:
55+
56+
```ts
57+
loginForm.email() // Returns FieldState with value(), valid(), touched(), etc.
58+
```
59+
60+
To read the field's current value, access the `value()` signal:
61+
62+
```html
63+
<!-- Render form value that updates automatically as user types -->
64+
<p>Email: {{ loginForm.email().value() }}</p>
65+
```
66+
67+
```ts
68+
// Get the current value
69+
const currentEmail = loginForm.email().value();
70+
```
71+
72+
### 5. Update field values with `set()`
73+
74+
You can programmatically update a field's value using the `value.set()` method. This updates both the field and the underlying model signal:
75+
76+
```ts
77+
// Update the value programmatically
78+
loginForm.email().value.set('alice@wonderland.com');
79+
```
80+
81+
As a result, both the field value and the model signal are updated automatically:
82+
83+
```ts
84+
// The model signal is also updated
85+
console.log(loginModel().email); // 'alice@wonderland.com'
86+
```
87+
88+
Here's a complete example:
89+
90+
<docs-code-multifile preview path="adev/src/content/examples/signal-forms/src/login-simple/app/app.ts">
91+
<docs-code header="app.ts" path="adev/src/content/examples/signal-forms/src/login-simple/app/app.ts"/>
92+
<docs-code header="app.html" path="adev/src/content/examples/signal-forms/src/login-simple/app/app.html"/>
93+
<docs-code header="app.css" path="adev/src/content/examples/signal-forms/src/login-simple/app/app.css"/>
94+
</docs-code-multifile>
95+
96+
## Basic usage
97+
98+
The `[field]` directive works with all standard HTML input types. Here are the most common patterns:
99+
100+
### Text inputs
101+
102+
Text inputs work with various `type` attributes and textareas:
103+
104+
```html
105+
<!-- Text and email -->
106+
<input type="text" [field]="form.name" />
107+
<input type="email" [field]="form.email" />
108+
```
109+
110+
#### Numbers
111+
112+
Number inputs automatically convert between strings and numbers:
113+
114+
```html
115+
<!-- Number - automatically converts to number type -->
116+
<input type="number" [field]="form.age" />
117+
```
118+
119+
#### Date and time
120+
121+
Date inputs store values as `YYYY-MM-DD` strings, and time inputs use `HH:mm` format:
122+
123+
```html
124+
<!-- Date and time - stores as ISO format strings -->
125+
<input type="date" [field]="form.eventDate" />
126+
<input type="time" [field]="form.eventTime" />
127+
```
128+
129+
If you need to convert date strings to Date objects, you can do so by passing the field value into `Date()`:
130+
131+
```ts
132+
const dateObject = new Date(form.eventDate().value());
133+
```
134+
135+
#### Multiline text
136+
137+
Textareas work the same way as text inputs:
138+
139+
```html
140+
<!-- Textarea -->
141+
<textarea [field]="form.message" rows="4"></textarea>
142+
```
143+
144+
### Checkboxes
145+
146+
Checkboxes bind to boolean values:
147+
148+
```html
149+
<!-- Single checkbox -->
150+
<label>
151+
<input type="checkbox" [field]="form.agreeToTerms" />
152+
I agree to the terms
153+
</label>
154+
```
155+
156+
#### Multiple checkboxes
157+
158+
For multiple options, create a separate boolean `field` for each:
159+
160+
```html
161+
<label>
162+
<input type="checkbox" [field]="form.emailNotifications" />
163+
Email notifications
164+
</label>
165+
<label>
166+
<input type="checkbox" [field]="form.smsNotifications" />
167+
SMS notifications
168+
</label>
169+
```
170+
171+
### Radio buttons
172+
173+
Radio buttons work similarly to checkboxes. As long as the radio buttons use the same `[field]` value, Signal Forms will automatically bind the same `name` attribute to all of them:
174+
175+
```html
176+
<label>
177+
<input type="radio" value="free" [field]="form.plan" />
178+
Free
179+
</label>
180+
<label>
181+
<input type="radio" value="premium" [field]="form.plan" />
182+
Premium
183+
</label>
184+
```
185+
186+
When a user selects a radio button, the form `field` stores the value from that radio button's `value` attribute. For example, selecting "Premium" sets `form.plan().value()` to `"premium"`.
187+
188+
### Select dropdowns
189+
190+
Select elements work with both static and dynamic options:
191+
192+
```html
193+
<!-- Static options -->
194+
<select [field]="form.country">
195+
<option value="">Select a country</option>
196+
<option value="us">United States</option>
197+
<option value="ca">Canada</option>
198+
</select>
199+
200+
<!-- Dynamic options with @for -->
201+
<select [field]="form.productId">
202+
<option value="">Select a product</option>
203+
@for (product of products; track product.id) {
204+
<option [value]="product.id">{{ product.name }}</option>
205+
}
206+
</select>
207+
```
208+
209+
NOTE: Multiple select (`<select multiple>`) is not supported by the `[field]` directive at this time.
210+
211+
## Validation and state
212+
213+
Signal Forms provides built-in validators that you can apply to your form fields. To add validation, pass a schema function as the second argument to `form()`:
214+
215+
```ts
216+
const loginForm = form(loginModel, (schemaPath) => {
217+
debounce(schemaPath.email, 500);
218+
required(schemaPath.email);
219+
email(schemaPath.email);
220+
});
221+
```
222+
223+
The schema function receives a **schema path** parameter that provides paths to your fields for configuring validation rules.
224+
225+
Common validators include:
226+
227+
- **`required()`** - Ensures the field has a value
228+
- **`email()`** - Validates email format
229+
- **`min()`** / **`max()`** - Validates number ranges
230+
- **`minLength()`** / **`maxLength()`** - Validates string or collection length
231+
- **`pattern()`** - Validates against a regex pattern
232+
233+
You can also customize error messages by passing an options object as the second argument to the validator:
234+
235+
```ts
236+
required(schemaPath.email, { message: 'Email is required' });
237+
email(schemaPath.email, { message: 'Please enter a valid email address' });
238+
```
239+
240+
Each form field exposes its validation state through signals. For example, you can check `field().valid()` to see if validation passes, `field().touched()` to see if the user has interacted with it, and `field().errors()` to get the list of validation errors.
241+
242+
Here's a complete example:
243+
244+
<docs-code-multifile preview path="adev/src/content/examples/signal-forms/src/login-validation/app/app.ts">
245+
<docs-code header="app.ts" path="adev/src/content/examples/signal-forms/src/login-validation/app/app.ts"/>
246+
<docs-code header="app.html" path="adev/src/content/examples/signal-forms/src/login-validation/app/app.html"/>
247+
<docs-code header="app.css" path="adev/src/content/examples/signal-forms/src/login-validation/app/app.css"/>
248+
</docs-code-multifile>
249+
250+
### Field State Signals
251+
252+
Every `field()` provides these state signals:
253+
254+
| State | Description |
255+
| ------------ | -------------------------------------------------------------------------- |
256+
| `valid()` | Returns `true` if the field passes all validation rules |
257+
| `touched()` | Returns `true` if the user has focused and blurred the field |
258+
| `dirty()` | Returns `true` if the user has changed the value |
259+
| `disabled()` | Returns `true` if the field is disabled |
260+
| `readonly()` | Returns `true` if the field is readonly |
261+
| `pending()` | Returns `true` if async validation is in progress |
262+
| `errors()` | Returns an array of validation errors with `kind` and `message` properties |
263+
264+
## Next steps
265+
266+
To learn more about Signal Forms and how it works, check out the in-depth guides:
267+
268+
- [Overview](guide/forms/signals/overview) - Introduction to Signal Forms and when to use them
269+
- [Form models](guide/forms/signals/models) - Creating and managing form data with signals
270+
- [Field state management](guide/forms/signals/field-state-management) - Working with validation state, interaction tracking, and field visibility
271+
- [Validation](guide/forms/signals/validation) - Built-in validators, custom validation rules, and async validation

0 commit comments

Comments
 (0)