Skip to content

Commit b23c31a

Browse files
authored
fix(forms): fix some things that g3 complains about (#63405)
* fix(forms): fix some things that g3 complains about * fixup! fix(forms): fix some things that g3 complains about
1 parent aef4b05 commit b23c31a

File tree

3 files changed

+52
-37
lines changed

3 files changed

+52
-37
lines changed

packages/forms/signals/src/controls/control.ts

Lines changed: 45 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
OutputRef,
2323
OutputRefSubscription,
2424
reflectComponentType,
25+
Renderer2,
2526
signal,
2627
Type,
2728
untracked,
@@ -37,7 +38,7 @@ import {
3738
PATTERN,
3839
REQUIRED,
3940
} from '../api/property';
40-
import {Field} from '../api/types';
41+
import type {Field} from '../api/types';
4142
import type {FieldNode} from '../field/node';
4243
import {
4344
illegallyGetComponentInstance,
@@ -75,6 +76,7 @@ import {InteropNgControl} from './interop_ng_control';
7576
export class Control<T> {
7677
/** The injector for this component. */
7778
private readonly injector = inject(Injector);
79+
private readonly renderer = inject(Renderer2);
7880

7981
/** Whether state synchronization with the field has been setup yet. */
8082
private initialized = false;
@@ -202,16 +204,25 @@ export class Control<T> {
202204
});
203205
input.addEventListener('blur', () => this.state().markAsTouched());
204206

205-
this.maybeSynchronize(() => this.state().readonly(), withBooleanAttribute(input, 'readonly'));
207+
this.maybeSynchronize(
208+
() => this.state().readonly(),
209+
this.withBooleanAttribute(input, 'readonly'),
210+
);
206211
// TODO: consider making a global configuration option for using aria-disabled instead.
207-
this.maybeSynchronize(() => this.state().disabled(), withBooleanAttribute(input, 'disabled'));
208-
this.maybeSynchronize(() => this.state().name(), withAttribute(input, 'name'));
212+
this.maybeSynchronize(
213+
() => this.state().disabled(),
214+
this.withBooleanAttribute(input, 'disabled'),
215+
);
216+
this.maybeSynchronize(() => this.state().name(), this.withAttribute(input, 'name'));
209217

210-
this.maybeSynchronize(this.propertySource(REQUIRED), withBooleanAttribute(input, 'required'));
211-
this.maybeSynchronize(this.propertySource(MIN), withAttribute(input, 'min'));
212-
this.maybeSynchronize(this.propertySource(MIN_LENGTH), withAttribute(input, 'minLength'));
213-
this.maybeSynchronize(this.propertySource(MAX), withAttribute(input, 'max'));
214-
this.maybeSynchronize(this.propertySource(MAX_LENGTH), withAttribute(input, 'maxLength'));
218+
this.maybeSynchronize(
219+
this.propertySource(REQUIRED),
220+
this.withBooleanAttribute(input, 'required'),
221+
);
222+
this.maybeSynchronize(this.propertySource(MIN), this.withAttribute(input, 'min'));
223+
this.maybeSynchronize(this.propertySource(MIN_LENGTH), this.withAttribute(input, 'minLength'));
224+
this.maybeSynchronize(this.propertySource(MAX), this.withAttribute(input, 'max'));
225+
this.maybeSynchronize(this.propertySource(MAX_LENGTH), this.withAttribute(input, 'maxLength'));
215226

216227
switch (inputType) {
217228
case 'checkbox':
@@ -360,38 +371,38 @@ export class Control<T> {
360371
);
361372
return () => metaSource()?.();
362373
}
374+
375+
/** Creates a (non-boolean) value sync that writes the given attribute of the given element. */
376+
private withAttribute(
377+
element: HTMLElement,
378+
attribute: string,
379+
): (value: {toString(): string} | undefined) => void {
380+
return (value) => {
381+
if (value !== undefined) {
382+
this.renderer.setAttribute(element, attribute, value.toString());
383+
} else {
384+
this.renderer.removeAttribute(element, attribute);
385+
}
386+
};
387+
}
388+
389+
/** Creates a boolean value sync that writes the given attribute of the given element. */
390+
private withBooleanAttribute(element: HTMLElement, attribute: string): (value: boolean) => void {
391+
return (value) => {
392+
if (value) {
393+
this.renderer.setAttribute(element, attribute, '');
394+
} else {
395+
this.renderer.removeAttribute(element, attribute);
396+
}
397+
};
398+
}
363399
}
364400

365401
/** Creates a value sync from an input signal. */
366402
function withInput<T>(input: InputSignal<T> | undefined): ((value: T) => void) | undefined {
367403
return input ? (value: T) => illegallySetInputSignal(input, value) : undefined;
368404
}
369405

370-
/** Creates a boolean value sync that writes the given attribute of the given element. */
371-
function withBooleanAttribute(element: HTMLElement, attribute: string): (value: boolean) => void {
372-
return (value) => {
373-
if (value) {
374-
element.setAttribute(attribute, '');
375-
} else {
376-
element.removeAttribute(attribute);
377-
}
378-
};
379-
}
380-
381-
/** Creates a (non-boolean) value sync that writes the given attribute of the given element. */
382-
function withAttribute(
383-
element: HTMLElement,
384-
attribute: string,
385-
): (value: {toString(): string} | undefined) => void {
386-
return (value) => {
387-
if (value !== undefined) {
388-
element.setAttribute(attribute, value.toString());
389-
} else {
390-
element.removeAttribute(attribute);
391-
}
392-
};
393-
}
394-
395406
/**
396407
* Checks whether the given component matches the contract for either FormValueControl or
397408
* FormCheckboxControl.

packages/forms/signals/src/field/context.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {Field, FieldContext, FieldPath, FieldState} from '../api/types';
1111
import {FieldPathNode} from '../schema/path_node';
1212
import {isArray} from '../util/type_guards';
1313
import type {FieldNode} from './node';
14-
import {boundPathDepth} from './resolution';
14+
import {getBoundPathDepth} from './resolution';
1515

1616
/**
1717
* `FieldContext` implementation, backed by a `FieldNode`.
@@ -49,7 +49,7 @@ export class FieldNodeContext implements FieldContext<unknown> {
4949
// This ensures that we do not accidentally match on the wrong application of a recursively
5050
// applied schema.
5151
let field: FieldNode | undefined = this.node;
52-
let stepsRemaining = boundPathDepth;
52+
let stepsRemaining = getBoundPathDepth();
5353
while (stepsRemaining > 0 || !field.structure.logic.hasLogic(targetPathNode.root.logic)) {
5454
stepsRemaining--;
5555
field = field.structure.parent;

packages/forms/signals/src/field/resolution.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9+
let boundPathDepth = 0;
10+
911
/**
1012
* The depth of the current path when evaluating a logic function.
1113
* Do not set this directly, it is a context variable managed by `setBoundPathDepthForResolution`.
1214
*/
13-
export let boundPathDepth = 0;
15+
export function getBoundPathDepth() {
16+
return boundPathDepth;
17+
}
1418

1519
/**
1620
* Sets the bound path depth for the duration of the given logic function.

0 commit comments

Comments
 (0)