Skip to content

Commit 39be060

Browse files
dylhunnalxhub
authored andcommitted
fix(forms): Add a nonNullable option to FormControl for consistency.
DEPRECATED: The `initialValueIsDefault` option has been deprecated and replaced with the otherwise-identical `nonNullable` option, for the sake of naming consistency.
1 parent 2bc6535 commit 39be060

File tree

6 files changed

+184
-162
lines changed

6 files changed

+184
-162
lines changed

aio/content/guide/typed-forms.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,10 @@ email.reset();
7272
console.log(email.value); // null
7373
```
7474

75-
TypeScript will enforce that you always handle the possibility that the control has become `null`. If you want to make this control non-nullable, you may use the `initialValueIsDefault` option. This will cause the control to reset to its intial value, instead of `null`:
75+
TypeScript will enforce that you always handle the possibility that the control has become `null`. If you want to make this control non-nullable, you may use the `nonNullable` option. This will cause the control to reset to its intial value, instead of `null`:
7676

7777
```ts
78-
const email = new FormControl('angularrox@gmail.com', {initialValueIsDefault: true});
78+
const email = new FormControl('angularrox@gmail.com', {nonNullable: true});
7979
email.reset();
8080
console.log(email.value); // angularrox@gmail.com
8181
```
@@ -125,8 +125,8 @@ Consider again a login form:
125125

126126
```ts
127127
const login = new FormGroup({
128-
email: new FormControl('', {initialValueIsDefault: true}),
129-
password: new FormControl('', {initialValueIsDefault: true}),
128+
email: new FormControl('', {nonNullable: true}),
129+
password: new FormControl('', {nonNullable: true}),
130130
});
131131
```
132132

@@ -149,8 +149,8 @@ interface LoginForm {
149149
}
150150

151151
const login = new FormGroup<LoginForm>({
152-
email: new FormControl('', {initialValueIsDefault: true}),
153-
password: new FormControl('', {initialValueIsDefault: true}),
152+
email: new FormControl('', {nonNullable: true}),
153+
password: new FormControl('', {nonNullable: true}),
154154
});
155155

156156
login.removeControl('password');
@@ -175,7 +175,7 @@ If you need a `FormGroup` that is both dynamic (open-ended) and heterogenous (th
175175

176176
The `FormBuilder` class has been upgraded to support the new types as well, in the same manner as the above examples.
177177

178-
Additionally, an additional builder is available: `NonNullableFormBuilder`. This type is shorthand for specifying `{initialValueIsDefault: true}` on every control, and can eliminate significant boilerplate from large non-nullable forms. You can access it using the `nonNullable` property on a `FormBuilder`:
178+
Additionally, an additional builder is available: `NonNullableFormBuilder`. This type is shorthand for specifying `{nonNullable: true}` on every control, and can eliminate significant boilerplate from large non-nullable forms. You can access it using the `nonNullable` property on a `FormBuilder`:
179179

180180
```ts
181181
const fb = new FormBuilder();
@@ -185,7 +185,7 @@ const login = fb.nonNullable.group({
185185
});
186186
```
187187

188-
On the above example, both inner controls will be non-nullable (i.e. `initialValueIsDefault` will be set).
188+
On the above example, both inner controls will be non-nullable (i.e. `nonNullable` will be set).
189189

190190
You can also inject it using the name `NonNullableFormBuilder`.
191191

goldens/public-api/forms/index.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,11 +277,15 @@ export class FormArrayName extends ControlContainer implements OnInit, OnDestroy
277277
// @public
278278
export class FormBuilder {
279279
array<T>(controls: Array<T>, validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null): FormArrayElement<T, null>>;
280-
// (undocumented)
280+
// @deprecated (undocumented)
281281
control<T>(formState: T | FormControlState<T>, opts: FormControlOptions & {
282282
initialValueIsDefault: true;
283283
}): FormControl<T>;
284284
// (undocumented)
285+
control<T>(formState: T | FormControlState<T>, opts: FormControlOptions & {
286+
nonNullable: true;
287+
}): FormControl<T>;
288+
// (undocumented)
285289
control<T>(formState: T | FormControlState<T>, validatorOrOpts?: ValidatorFn | ValidatorFn[] | FormControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null): FormControl<T | null>;
286290
group<T extends {}>(controls: T, options?: AbstractControlOptions | null): FormGroup<{
287291
[K in keyof T]: ɵElement<T[K], null>;
@@ -374,7 +378,9 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy {
374378

375379
// @public
376380
export interface FormControlOptions extends AbstractControlOptions {
381+
// @deprecated (undocumented)
377382
initialValueIsDefault?: boolean;
383+
nonNullable?: boolean;
378384
}
379385

380386
// @public

packages/forms/src/form_builder.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ function isFormControlOptions(options: FormControlOptions|{[key: string]: any}|n
2727
undefined): options is FormControlOptions {
2828
return !!options &&
2929
(isAbstractControlOptions(options) ||
30-
(options as FormControlOptions).initialValueIsDefault !== undefined);
30+
(options as FormControlOptions).initialValueIsDefault !== undefined ||
31+
(options as FormControlOptions).nonNullable !== undefined);
3132
}
3233

3334
/**
@@ -85,7 +86,7 @@ export class FormBuilder {
8586
/**
8687
* @description
8788
* Returns a FormBuilder in which automatically constructed @see FormControl} elements
88-
* have `{initialValueIsDefault: true}` and are non-nullable.
89+
* have `{nonNullable: true}` and are non-nullable.
8990
*
9091
* **Constructing non-nullable controls**
9192
*
@@ -205,10 +206,14 @@ export class FormBuilder {
205206
return new FormGroup(reducedControls, {asyncValidators, updateOn, validators}) as any;
206207
}
207208

209+
/** @deprecated Use `nonNullable` instead. */
208210
control<T>(formState: T|FormControlState<T>, opts: FormControlOptions&{
209211
initialValueIsDefault: true
210212
}): FormControl<T>;
211213

214+
control<T>(formState: T|FormControlState<T>, opts: FormControlOptions&{nonNullable: true}):
215+
FormControl<T>;
216+
212217
control<T>(
213218
formState: T|FormControlState<T>,
214219
validatorOrOpts?: ValidatorFn|ValidatorFn[]|FormControlOptions|null,
@@ -217,7 +222,7 @@ export class FormBuilder {
217222
/**
218223
* @description
219224
* Construct a new `FormControl` with the given state, validators and options. Set
220-
* `{initialValueIsDefault: true}` in the options to get a non-nullable control. Otherwise, the
225+
* `{nonNullable: true}` in the options to get a non-nullable control. Otherwise, the
221226
* control will be nullable. Accepts a single generic argument, which is the type of the
222227
* control's value.
223228
*
@@ -256,7 +261,7 @@ export class FormBuilder {
256261
newOptions.validators = validatorOrOpts;
257262
newOptions.asyncValidators = asyncValidator;
258263
}
259-
return new FormControl<T>(formState, {...newOptions, initialValueIsDefault: true});
264+
return new FormControl<T>(formState, {...newOptions, nonNullable: true});
260265
}
261266

262267
/**
@@ -314,7 +319,7 @@ export class FormBuilder {
314319
/**
315320
* @description
316321
* `NonNullableFormBuilder` is similar to {@link FormBuilder}, but automatically constructed
317-
* {@link FormControl} elements have `{initialValueIsDefault: true}` and are non-nullable.
322+
* {@link FormControl} elements have `{nonNullable: true}` and are non-nullable.
318323
*
319324
* @publicApi
320325
*/
@@ -325,7 +330,7 @@ export class FormBuilder {
325330
export abstract class NonNullableFormBuilder {
326331
/**
327332
* Similar to `FormBuilder#group`, except any implicitly constructed `FormControl`
328-
* will be non-nullable (i.e. it will have `initialValueIsDefault` set to true). Note
333+
* will be non-nullable (i.e. it will have `nonNullable` set to true). Note
329334
* that already-constructed controls will not be altered.
330335
*/
331336
abstract group<T extends {}>(
@@ -335,7 +340,7 @@ export abstract class NonNullableFormBuilder {
335340

336341
/**
337342
* Similar to `FormBuilder#array`, except any implicitly constructed `FormControl`
338-
* will be non-nullable (i.e. it will have `initialValueIsDefault` set to true). Note
343+
* will be non-nullable (i.e. it will have `nonNullable` set to true). Note
339344
* that already-constructed controls will not be altered.
340345
*/
341346
abstract array<T>(
@@ -344,7 +349,7 @@ export abstract class NonNullableFormBuilder {
344349

345350
/**
346351
* Similar to `FormBuilder#control`, except this overridden version of `control` forces
347-
* `initialValueIsDefault` to be `true`, resulting in the control always being non-nullable.
352+
* `nonNullable` to be `true`, resulting in the control always being non-nullable.
348353
*/
349354
abstract control<T>(
350355
formState: T|FormControlState<T>,

packages/forms/src/model/form_control.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ export interface FormControlOptions extends AbstractControlOptions {
3737
* When a FormControl is reset without an explicit value, its value reverts to
3838
* its default value.
3939
*/
40+
nonNullable?: boolean;
41+
42+
/**
43+
* @deprecated Use `nonNullable` instead.
44+
*/
4045
initialValueIsDefault?: boolean;
4146
}
4247

@@ -50,7 +55,7 @@ export interface FormControlOptions extends AbstractControlOptions {
5055
*
5156
* `FormControl` takes a single generic argument, which describes the type of its value. This
5257
* argument always implicitly includes `null` because the control can be reset. To change this
53-
* behavior, set `initialValueIsDefault` or see the usage notes below.
58+
* behavior, set `nonNullable` or see the usage notes below.
5459
*
5560
* See [usage examples below](#usage-notes).
5661
*
@@ -114,7 +119,7 @@ export interface FormControlOptions extends AbstractControlOptions {
114119
*
115120
* You might notice that `null` is always added to the type of the control.
116121
* This is because the control will become `null` if you call `reset`. You can change
117-
* this behavior by setting `{initialValueIsDefault: true}`.
122+
* this behavior by setting `{nonNullable: true}`.
118123
*
119124
* ### Configure the control to update on a blur event
120125
*
@@ -151,10 +156,10 @@ export interface FormControlOptions extends AbstractControlOptions {
151156
* ### Reset the control to its initial value
152157
*
153158
* If you wish to always reset the control to its initial value (instead of null),
154-
* you can pass the `initialValueIsDefault` option:
159+
* you can pass the `nonNullable` option:
155160
*
156161
* ```
157-
* const control = new FormControl('Nancy', {initialValueIsDefault: true});
162+
* const control = new FormControl('Nancy', {nonNullable: true});
158163
*
159164
* console.log(control.value); // 'Nancy'
160165
*
@@ -180,7 +185,7 @@ export interface FormControlOptions extends AbstractControlOptions {
180185
export interface FormControl<TValue = any> extends AbstractControl<TValue> {
181186
/**
182187
* The default value of this FormControl, used whenever the control is reset without an explicit
183-
* value. See {@link FormControlOptions#initialValueIsDefault} for more information on configuring
188+
* value. See {@link FormControlOptions#nonNullable} for more information on configuring
184189
* a default value.
185190
*/
186191
readonly defaultValue: TValue;
@@ -246,19 +251,19 @@ export interface FormControl<TValue = any> extends AbstractControl<TValue> {
246251
/**
247252
* Resets the form control, marking it `pristine` and `untouched`, and resetting
248253
* the value. The new value will be the provided value (if passed), `null`, or the initial value
249-
* if `initialValueIsDefault` was set in the constructor via {@link FormControlOptions}.
254+
* if `nonNullable` was set in the constructor via {@link FormControlOptions}.
250255
*
251256
* ```ts
252257
* // By default, the control will reset to null.
253258
* const dog = new FormControl('spot');
254259
* dog.reset(); // dog.value is null
255260
*
256261
* // If this flag is set, the control will instead reset to the initial value.
257-
* const cat = new FormControl('tabby', {initialValueIsDefault: true});
262+
* const cat = new FormControl('tabby', {nonNullable: true});
258263
* cat.reset(); // cat.value is "tabby"
259264
*
260265
* // A value passed to reset always takes precedence.
261-
* const fish = new FormControl('finn', {initialValueIsDefault: true});
266+
* const fish = new FormControl('finn', {nonNullable: true});
262267
* fish.reset('bubble'); // fish.value is "bubble"
263268
* ```
264269
*
@@ -368,6 +373,11 @@ export interface ɵFormControlCtor {
368373
*
369374
* @param asyncValidator A single async validator or array of async validator functions
370375
*/
376+
new<T = any>(value: FormControlState<T>|T, opts: FormControlOptions&{nonNullable: true}):
377+
FormControl<T>;
378+
/**
379+
* @deprecated Use `nonNullable` instead.
380+
*/
371381
new<T = any>(value: FormControlState<T>|T, opts: FormControlOptions&{
372382
initialValueIsDefault: true
373383
}): FormControl<T>;
@@ -421,7 +431,8 @@ export const FormControl: ɵFormControlCtor =
421431
// `emitEvent` to `true` to allow that during the control creation process.
422432
emitEvent: !!this.asyncValidator
423433
});
424-
if (isOptionsObj(validatorOrOpts) && validatorOrOpts.initialValueIsDefault) {
434+
if (isOptionsObj(validatorOrOpts) &&
435+
(validatorOrOpts.nonNullable || validatorOrOpts.initialValueIsDefault)) {
425436
if (isFormControlState(formState)) {
426437
this.defaultValue = formState.value;
427438
} else {

packages/forms/test/form_control_spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,7 @@ describe('FormControl', () => {
817817
});
818818

819819
it('should reset to the initial value if specified in FormControlOptions', () => {
820-
const c2 = new FormControl('foo', {initialValueIsDefault: true});
820+
const c2 = new FormControl('foo', {nonNullable: true});
821821
expect(c2.value).toBe('foo');
822822
expect(c2.defaultValue).toBe('foo');
823823

@@ -829,7 +829,7 @@ describe('FormControl', () => {
829829
expect(c2.value).toBe('foo');
830830
expect(c2.defaultValue).toBe('foo');
831831

832-
const c3 = new FormControl('foo', {initialValueIsDefault: false});
832+
const c3 = new FormControl('foo', {nonNullable: false});
833833
expect(c3.value).toBe('foo');
834834
expect(c3.defaultValue).toBe(null);
835835

@@ -858,7 +858,7 @@ describe('FormControl', () => {
858858

859859
it('should not alter the disabled state when resetting, even if a default value is provided',
860860
() => {
861-
const c2 = new FormControl({value: 'foo', disabled: true}, {initialValueIsDefault: true});
861+
const c2 = new FormControl({value: 'foo', disabled: true}, {nonNullable: true});
862862
expect(c2.value).toBe('foo');
863863
expect(c2.defaultValue).toBe('foo');
864864
expect(c2.disabled).toBe(true);

0 commit comments

Comments
 (0)