Visitar URL original
feat(forms): allow permanent hidden fields in signal forms · angular/angular@d5e8b1e · GitHub
Skip to content

Commit d5e8b1e

Browse files
brysonbwalxhub
authored andcommitted
feat(forms): allow permanent hidden fields in signal forms
Allow the hidden utility function to be called without a configuration object to make fields permanently hidden.
1 parent f33ee95 commit d5e8b1e

4 files changed

Lines changed: 64 additions & 8 deletions

File tree

‎adev/src/content/guide/forms/signals/form-logic.md‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,45 @@ export class Profile {
221221
}
222222
```
223223

224+
### Always hidden
225+
226+
To make a field permanently hidden, call `hidden()` with just the field path:
227+
228+
```angular-ts
229+
import {Component, signal} from '@angular/core';
230+
import {form, FormField, hidden} from '@angular/forms/signals';
231+
232+
@Component({
233+
selector: 'app-profile',
234+
imports: [FormField],
235+
template: `
236+
<label>
237+
<input type="checkbox" [formField]="profileForm.isPublic" />
238+
Make profile public
239+
</label>
240+
241+
<!-- The publicUrl is permanently hidden, so this block never renders -->
242+
@if (!profileForm.publicUrl().hidden()) {
243+
<label>
244+
Public URL
245+
<input [formField]="profileForm.publicUrl" />
246+
</label>
247+
}
248+
`,
249+
})
250+
export class Profile {
251+
profileModel = signal({
252+
isPublic: false,
253+
publicUrl: '',
254+
});
255+
256+
profileForm = form(this.profileModel, (schemaPath) => {
257+
// This field is now permanently hidden and excluded from active validation
258+
hidden(schemaPath.publicUrl);
259+
});
260+
}
261+
```
262+
224263
## Display uneditable fields with `readonly()`
225264

226265
The `readonly()` rule prevents users from updating a field. The `[FormField]` directive automatically binds this state to the HTML `readonly` attribute, which prevents editing while still allowing users to focus and select text.

‎goldens/public-api/forms/signals/index.api.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -274,12 +274,12 @@ export interface FormValueControl<TValue> extends FormUiControl<TValue> {
274274
}
275275

276276
// @public
277-
export function hidden<TValue, TPathKind extends PathKind = PathKind.Root>(path: SchemaPath<TValue, SchemaPathRules.Supported, TPathKind>, config: {
278-
when: NoInfer<LogicFn<TValue, boolean, TPathKind>>;
277+
export function hidden<TValue, TPathKind extends PathKind = PathKind.Root>(path: SchemaPath<TValue, SchemaPathRules.Supported, TPathKind>, config?: {
278+
when?: NoInfer<LogicFn<TValue, boolean, TPathKind>>;
279279
}): void;
280280

281281
// @public @deprecated
282-
export function hidden<TValue, TPathKind extends PathKind = PathKind.Root>(path: SchemaPath<TValue, SchemaPathRules.Supported, TPathKind>, logic: NoInfer<LogicFn<TValue, boolean, TPathKind>>): void;
282+
export function hidden<TValue, TPathKind extends PathKind = PathKind.Root>(path: SchemaPath<TValue, SchemaPathRules.Supported, TPathKind>, logic?: NoInfer<LogicFn<TValue, boolean, TPathKind>>): void;
283283

284284
// @public
285285
export interface HttpValidatorOptions<TValue, TResult, TPathKind extends PathKind = PathKind.Root> {

‎packages/forms/signals/src/api/rules/hidden.ts‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import type {LogicFn, PathKind, SchemaPath, SchemaPathRules} from '../types';
3636
*/
3737
export function hidden<TValue, TPathKind extends PathKind = PathKind.Root>(
3838
path: SchemaPath<TValue, SchemaPathRules.Supported, TPathKind>,
39-
config: {when: NoInfer<LogicFn<TValue, boolean, TPathKind>>},
39+
config?: {when?: NoInfer<LogicFn<TValue, boolean, TPathKind>>},
4040
): void;
4141

4242
/**
@@ -46,20 +46,21 @@ export function hidden<TValue, TPathKind extends PathKind = PathKind.Root>(
4646
*/
4747
export function hidden<TValue, TPathKind extends PathKind = PathKind.Root>(
4848
path: SchemaPath<TValue, SchemaPathRules.Supported, TPathKind>,
49-
logic: NoInfer<LogicFn<TValue, boolean, TPathKind>>,
49+
logic?: NoInfer<LogicFn<TValue, boolean, TPathKind>>,
5050
): void;
5151

5252
export function hidden<TValue, TPathKind extends PathKind = PathKind.Root>(
5353
path: SchemaPath<TValue, SchemaPathRules.Supported, TPathKind>,
54-
configOrLogic:
55-
| {when: NoInfer<LogicFn<TValue, boolean, TPathKind>>}
54+
configOrLogic?:
55+
| {when?: NoInfer<LogicFn<TValue, boolean, TPathKind>>}
5656
| NoInfer<LogicFn<TValue, boolean, TPathKind>>,
5757
): void {
5858
assertPathIsCurrent(path);
5959

6060
const pathNode = FieldPathNode.unwrapFieldPath(path);
6161

62-
const logic = typeof configOrLogic === 'function' ? configOrLogic : configOrLogic.when;
62+
const logic =
63+
typeof configOrLogic === 'function' ? configOrLogic : (configOrLogic?.when ?? (() => true));
6364

6465
pathNode.builder.addHiddenRule(logic);
6566
}

‎packages/forms/signals/test/node/api/hidden.spec.ts‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,20 @@ describe('hidden', () => {
139139
f.name().value.set('hidden-cat');
140140
expect(f.name().hidden()).toBe(true);
141141
});
142+
143+
it('it returns true when configOrLogic is omitted', () => {
144+
const cat = signal({name: 'Pirojok-the-cat', age: 5});
145+
const f = form(
146+
cat,
147+
(p) => {
148+
hidden(p.name);
149+
},
150+
{injector: TestBed.inject(Injector)},
151+
);
152+
153+
expect(f.name().hidden()).withContext('Name is permanently hidden').toBeTrue();
154+
155+
f.name().value.set('some-other-cat');
156+
expect(f.name().hidden()).toBeTrue();
157+
});
142158
});

0 commit comments

Comments
 (0)