Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(forms): remove ngForm element selector #33058

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
38 changes: 11 additions & 27 deletions aio/content/guide/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ v8 - v11
| `@angular/core` | [`ReflectiveKey`](#core) | <!--v8--> v9 |
| `@angular/core` | [`RenderComponentType`](#core) | <!--v7--> v9 |
| `@angular/core` | [`ViewEncapsulation.Native`](#core) | v9 |
| `@angular/forms` | [`ngForm` element selector](#ngform) | v9 |
| `@angular/forms` | [`NgFormSelectorWarning`](#forms) | v9 |
| `@angular/forms` | [`ngModel` with reactive forms](#ngmodel-reactive) | v9 |
| `@angular/router` | [`preserveQueryParams`](#router) | <!--v7--> v9 |
| `@angular/upgrade` | [`@angular/upgrade`](#upgrade) | <!--v8--> v9 |
Expand Down Expand Up @@ -107,7 +105,6 @@ Tip: In the [API reference section](api) of this doc site, deprecated APIs are i

| API | Replacement | Deprecation announced | Notes |
| --- | ----------- | --------------------- | ----- |
| [`NgFormSelectorWarning`](api/forms/NgFormSelectorWarning) | n/a | v6 | See [ngForm](#ngform). |

{@a router}
### @angular/router
Expand Down Expand Up @@ -176,27 +173,6 @@ The `<template>` tag was deprecated in v4 to avoid colliding with the DOM's elem



{@a ngform}
### ngForm element selector

Support for using `ngForm` element selector was deprecated in v6.
It has been deprecated to be consistent with other core Angular selectors, which are typically written in kebab-case.

Deprecated:

```
<ngForm #myForm="ngForm">
```

Replacement:

```
<ng-form #myForm="ngForm">
```

The [`NgFormSelectorWarning`](api/forms/NgFormSelectorWarning) directive is solely used to display warnings when the deprecated `ngForm` selector is used.


{@a ngmodel-reactive}
### ngModel with reactive forms

Expand Down Expand Up @@ -405,9 +381,17 @@ The following APIs have been removed starting with version 8.0.0:
| `@angular/core/testing` | [`TestBed.deprecatedOverrideProvider()`](https://v7.angular.io/api/core/testing/TestBed#deprecatedoverrideprovider) | [`TestBed.overrideProvider()`](api/core/testing/TestBed#overrideprovider) | none |
| `@angular/core/testing` | [`TestBedStatic.deprecatedOverrideProvider()`](https://v7.angular.io/api/core/testing/TestBedStatic#deprecatedoverrideprovider) | [`TestBedStatic.overrideProvider()`](api/core/testing/TestBedStatic#overrideprovider) | none |
| `@angular/service-worker` | `versionedFiles` | `files` | In the service worker configuration file `ngsw-config.json`, replace `versionedFiles` with `files`. See [Service Worker Configuration](guide/service-worker-config#assetgroups). |
| `@angular/core` | [`Renderer`](https://v8.angular.io/api/core/Renderer) | [`Renderer2`](https://angular.io/api/core/Renderer2) | [Migration guide.](guide/migration-renderer)
| `@angular/core` | [`RootRenderer`](https://v8.angular.io/api/core/RootRenderer) | [`RendererFactory2`](https://angular.io/api/core/RendererFactory2) | none
| `@angular/core` | [`RenderComponentType`](https://v8.angular.io/api/core/RenderComponentType) | [`RendererType2`](https://angular.io/api/core/RendererType2) | none


The following APIs have been removed starting with version 9.0.0:

| Package | API | Replacement | Notes |
| ------- | -------------- | ----------- | ----- |
| `@angular/core` | [`Renderer`](https://v8.angular.io/api/core/Renderer) | [`Renderer2`](https://angular.io/api/core/Renderer2) | [Migration guide.](guide/migration-renderer)
| `@angular/core` | [`RootRenderer`](https://v8.angular.io/api/core/RootRenderer) | [`RendererFactory2`](https://angular.io/api/core/RendererFactory2) | none
| `@angular/core` | [`RenderComponentType`](https://v8.angular.io/api/core/RenderComponentType) | [`RendererType2`](https://angular.io/api/core/RendererType2) | none
| `@angular/forms` | [`NgFormSelectorWarning`](https://v8.angular.io/api/forms/NgFormSelectorWarning) | none | none
crisbeto marked this conversation as resolved.
Show resolved Hide resolved
| `@angular/forms` | `ngForm` element selector | `ng-form` element selector | none


<!-- The following anchor is used by redirects from the removed API pages. Do not change or remove. -->
kara marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
5 changes: 1 addition & 4 deletions packages/forms/src/directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor
import {DefaultValueAccessor} from './directives/default_value_accessor';
import {NgControlStatus, NgControlStatusGroup} from './directives/ng_control_status';
import {NgForm} from './directives/ng_form';
import {NgFormSelectorWarning} from './directives/ng_form_selector_warning';
import {NgModel} from './directives/ng_model';
import {NgModelGroup} from './directives/ng_model_group';
import {NgNoValidate} from './directives/ng_no_validate_directive';
Expand All @@ -33,7 +32,6 @@ export {DefaultValueAccessor} from './directives/default_value_accessor';
export {NgControl} from './directives/ng_control';
export {NgControlStatus, NgControlStatusGroup} from './directives/ng_control_status';
export {NgForm} from './directives/ng_form';
export {NG_FORM_SELECTOR_WARNING, NgFormSelectorWarning} from './directives/ng_form_selector_warning';
export {NgModel} from './directives/ng_model';
export {NgModelGroup} from './directives/ng_model_group';
export {NumberValueAccessor} from './directives/number_value_accessor';
Expand Down Expand Up @@ -67,8 +65,7 @@ export const SHARED_FORM_DIRECTIVES: Type<any>[] = [
EmailValidator,
];

export const TEMPLATE_DRIVEN_DIRECTIVES: Type<any>[] =
[NgModel, NgModelGroup, NgForm, NgFormSelectorWarning];
export const TEMPLATE_DRIVEN_DIRECTIVES: Type<any>[] = [NgModel, NgModelGroup, NgForm];

export const REACTIVE_DRIVEN_DIRECTIVES: Type<any>[] =
[FormControlDirective, FormGroupDirective, FormControlName, FormGroupName, FormArrayName];
Expand Down
2 changes: 1 addition & 1 deletion packages/forms/src/directives/ng_form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const resolvedPromise = (() => Promise.resolve(null))();
* @publicApi
*/
@Directive({
selector: 'form:not([ngNoForm]):not([formGroup]),ngForm,ng-form,[ngForm]',
selector: 'form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]',
providers: [formDirectiveProvider],
host: {'(submit)': 'onSubmit($event)', '(reset)': 'onReset()'},
outputs: ['ngSubmit'],
Expand Down
42 changes: 0 additions & 42 deletions packages/forms/src/directives/ng_form_selector_warning.ts

This file was deleted.

17 changes: 0 additions & 17 deletions packages/forms/src/directives/template_driven_errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,4 @@ export class TemplateDrivenErrors {

${Examples.ngModelGroup}`);
}

static ngFormWarning() {
console.warn(`
It looks like you're using 'ngForm'.

Support for using the 'ngForm' element selector has been deprecated in Angular v6 and will be removed
in Angular v9.

Use 'ng-form' instead.

Before:
<ngForm #myForm="ngForm">

After:
<ng-form #myForm="ngForm">
`);
}
}
19 changes: 1 addition & 18 deletions packages/forms/src/form_providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import {ModuleWithProviders, NgModule} from '@angular/core';

import {InternalFormsSharedModule, NG_FORM_SELECTOR_WARNING, NG_MODEL_WITH_FORM_CONTROL_WARNING, REACTIVE_DRIVEN_DIRECTIVES, TEMPLATE_DRIVEN_DIRECTIVES} from './directives';
import {InternalFormsSharedModule, NG_MODEL_WITH_FORM_CONTROL_WARNING, REACTIVE_DRIVEN_DIRECTIVES, TEMPLATE_DRIVEN_DIRECTIVES} from './directives';
import {RadioControlRegistry} from './directives/radio_control_value_accessor';
import {FormBuilder} from './form_builder';

Expand All @@ -26,23 +26,6 @@ import {FormBuilder} from './form_builder';
exports: [InternalFormsSharedModule, TEMPLATE_DRIVEN_DIRECTIVES]
})
export class FormsModule {
/**
* @description
* Provides options for configuring the template-driven forms module.
*
* @param opts An object of configuration options
* * `warnOnDeprecatedNgFormSelector` Configures when to emit a warning when the deprecated
* `ngForm` selector is used.
*/
static withConfig(opts: {
/** @deprecated as of v6 */ warnOnDeprecatedNgFormSelector?: 'never' | 'once' | 'always',
}): ModuleWithProviders<FormsModule> {
return {
ngModule: FormsModule,
providers:
[{provide: NG_FORM_SELECTOR_WARNING, useValue: opts.warnOnDeprecatedNgFormSelector}]
};
}
}

/**
Expand Down
1 change: 0 additions & 1 deletion packages/forms/src/forms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ export {Form} from './directives/form_interface';
export {NgControl} from './directives/ng_control';
export {NgControlStatus, NgControlStatusGroup} from './directives/ng_control_status';
export {NgForm} from './directives/ng_form';
export {NgFormSelectorWarning} from './directives/ng_form_selector_warning';
export {NgModel} from './directives/ng_model';
export {NgModelGroup} from './directives/ng_model_group';
export {ɵNgNoValidate} from './directives/ng_no_validate_directive';
Expand Down
57 changes: 1 addition & 56 deletions packages/forms/test/template_integration_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import {ɵgetDOM as getDOM} from '@angular/common';
import {Component, Directive, Type, forwardRef} from '@angular/core';
import {ComponentFixture, TestBed, async, fakeAsync, tick} from '@angular/core/testing';
import {AbstractControl, AsyncValidator, COMPOSITION_BUFFER_MODE, FormControl, FormsModule, NG_ASYNC_VALIDATORS, NgForm, NgFormSelectorWarning, NgModel} from '@angular/forms';
import {AbstractControl, AsyncValidator, COMPOSITION_BUFFER_MODE, FormControl, FormsModule, NG_ASYNC_VALIDATORS, NgForm, NgModel} from '@angular/forms';
import {By} from '@angular/platform-browser/src/dom/debug/by';
import {dispatchEvent, sortedClassList} from '@angular/platform-browser/testing/src/browser_util';
import {merge} from 'rxjs';
Expand Down Expand Up @@ -1630,61 +1630,6 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat
}));
});

describe('ngForm deprecation warnings', () => {
let warnSpy: jasmine.Spy;

@Component({selector: 'ng-form-deprecated', template: `<ngForm></ngForm><ngForm></ngForm>`})
class ngFormDeprecated {
}

beforeEach(() => {
(NgFormSelectorWarning as any)._ngFormWarning = false;

warnSpy = spyOn(console, 'warn');
});

describe(`when using the deprecated 'ngForm' selector`, () => {
it(`should only warn once when global provider is provided with "once"`, () => {
TestBed.configureTestingModule({
declarations: [ngFormDeprecated],
imports: [FormsModule.withConfig({warnOnDeprecatedNgFormSelector: 'once'})]
});
TestBed.createComponent(ngFormDeprecated);
expect(warnSpy).toHaveBeenCalledTimes(1);
expect(warnSpy.calls.mostRecent().args[0])
.toMatch(/It looks like you're using 'ngForm'/gi);
});

it(`should only warn once by default`, () => {
initTest(ngFormDeprecated);
expect(warnSpy).toHaveBeenCalledTimes(1);
expect(warnSpy.calls.mostRecent().args[0])
.toMatch(/It looks like you're using 'ngForm'/gi);
});

it(`should not warn when global provider is provided with "never"`, () => {
TestBed.configureTestingModule({
declarations: [ngFormDeprecated],
imports: [FormsModule.withConfig({warnOnDeprecatedNgFormSelector: 'never'})]
});
TestBed.createComponent(ngFormDeprecated);
expect(warnSpy).not.toHaveBeenCalled();
});

it(`should only warn for each instance when global provider is provided with "always"`,
() => {
TestBed.configureTestingModule({
declarations: [ngFormDeprecated],
imports: [FormsModule.withConfig({warnOnDeprecatedNgFormSelector: 'always'})]
});

TestBed.createComponent(ngFormDeprecated);
expect(warnSpy).toHaveBeenCalledTimes(2);
expect(warnSpy.calls.mostRecent().args[0])
.toMatch(/It looks like you're using 'ngForm'/gi);
});
});
});
});
}

Expand Down
7 changes: 0 additions & 7 deletions tools/public_api_guard/forms/forms.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,6 @@ export declare class FormGroupName extends AbstractFormGroupDirective implements
}

export declare class FormsModule {
static withConfig(opts: { warnOnDeprecatedNgFormSelector?: 'never' | 'once' | 'always';
}): ModuleWithProviders<FormsModule>;
}

export declare class MaxLengthValidator implements Validator, OnChanges {
Expand Down Expand Up @@ -397,11 +395,6 @@ export declare class NgForm extends ControlContainer implements Form, AfterViewI
updateModel(dir: NgControl, value: any): void;
}

/** @deprecated */
export declare class NgFormSelectorWarning {
constructor(ngFormWarning: string | null);
}

export declare class NgModel extends NgControl implements OnChanges, OnDestroy {
readonly asyncValidator: AsyncValidatorFn | null;
readonly control: FormControl;
Expand Down