parent
ad178c55fd
commit
bd679581e2
|
@ -842,6 +842,7 @@ testing/** @angular/fw-test
|
|||
/aio/content/guide/workspace-config.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/deprecations.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/migration-renderer.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
/aio/content/guide/migration-undecorated-classes.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes
|
||||
|
||||
|
||||
# ================================================
|
||||
|
|
|
@ -397,6 +397,9 @@ This includes both packages: `@angular/platform-webworker` and
|
|||
|
||||
See the [dedicated migration guide for Renderer](guide/migration-renderer).
|
||||
|
||||
{@a undecorated-classes}
|
||||
### Migrating undecorated classes
|
||||
See the [dedicated migration guide for undecorated classes](guide/migration-undecorated-classes).
|
||||
|
||||
{@a removed}
|
||||
## Removed APIs
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
# Undecorated classes migration (DI)
|
||||
|
||||
This section discusses an Angular version 9 schematic that migrates
|
||||
two inheritance patterns that need to be updated to work with Ivy.
|
||||
|
||||
## What does this migration do?
|
||||
|
||||
This migration adds an empty `@Directive()` decorator to undecorated
|
||||
base classes that are extended by either directives or components.
|
||||
|
||||
Before:
|
||||
```ts
|
||||
export class BaseMenu {
|
||||
constructor(private vcr: ViewContainerRef) {}
|
||||
}
|
||||
|
||||
@Directive({selector: '[settingsMenu]'})
|
||||
export class SettingsMenu extends BaseMenu {}
|
||||
```
|
||||
|
||||
After:
|
||||
```ts
|
||||
@Directive()
|
||||
export class BaseMenu {
|
||||
constructor(private vcr: ViewContainerRef) {}
|
||||
}
|
||||
|
||||
@Directive({selector: '[settingsMenu]'})
|
||||
export class SettingsMenu extends BaseMenu {}
|
||||
```
|
||||
|
||||
The schematic also copies any inherited directive or component metadata to the derived class.
|
||||
|
||||
Before:
|
||||
```ts
|
||||
@Component({
|
||||
selector: 'base-menu',
|
||||
template: '<div></div>'
|
||||
})
|
||||
class BaseMenu {}
|
||||
|
||||
export class SettingsMenu extends BaseMenu {}
|
||||
```
|
||||
|
||||
After:
|
||||
```ts
|
||||
@Component({
|
||||
selector: 'base-menu',
|
||||
template: '<div></div>'
|
||||
})
|
||||
class BaseMenu {}
|
||||
|
||||
@Component({
|
||||
selector: 'settings-menu',
|
||||
template: '<div></div>'
|
||||
})
|
||||
export class SettingsMenu extends BaseMenu {}
|
||||
```
|
||||
|
||||
## Why is this migration necessary?
|
||||
|
||||
When a class has a `@Directive()` or `@Component()` decorator,
|
||||
the Angular compiler generates extra code to inject dependencies into
|
||||
the constructor. When using inheritance, Ivy needs both the parent class
|
||||
and the child class to apply a decorator to generate the correct code.
|
||||
|
||||
You can think of this change as two cases: a parent class is missing a
|
||||
decorator or a child class is missing a decorator. In both scenarios,
|
||||
Angular's run-time needs additional information from the compiler.
|
||||
This additional information comes from adding decorators.
|
||||
|
||||
|
||||
### Decorator missing from parent class
|
||||
|
||||
When the decorator is missing from the parent class,
|
||||
the subclass will inherit a constructor from a class for
|
||||
which the compiler did not generate special constructor
|
||||
info (because it was not decorated as a directive).
|
||||
When Angular then tries to create the subclass,
|
||||
it doesn't have the correct info
|
||||
to create it.
|
||||
|
||||
In View Engine, the compiler has global knowledge, so it
|
||||
can look up the missing data. However, the Ivy compiler
|
||||
only processes each directive in isolation. This means that
|
||||
compilation can be faster, but the compiler can't
|
||||
automatically infer the same
|
||||
information as before. Adding the `@Directive()` explicitly
|
||||
provides this information.
|
||||
|
||||
In the future, add `@Directive()` to base classes that
|
||||
do not already have decorators and are extended by directives.
|
||||
|
||||
### Decorator missing from child class
|
||||
|
||||
When the child class is missing the decorator, the
|
||||
child class inherits from the
|
||||
parent class yet has no decorators of its own.
|
||||
Without a decorator, the compiler has no way of knowing
|
||||
that the class is a `@Directive` or `@Component`, so
|
||||
it doesn't generate the proper instructions for the directive.
|
||||
|
||||
|
||||
## What does it mean to have a `@Directive()` decorator with no metadata inside of it?
|
||||
|
||||
The presence of the `@Directive` decorator causes Angular to generate
|
||||
extra code for the affected class. If that decorator includes no
|
||||
properties (metadata),
|
||||
the directive won't be matched to elements or instantiated
|
||||
directly, but other classes that _extend_ the
|
||||
directive class will inherit this generated code. You can think of
|
||||
this as an "abstract" directive.
|
||||
|
||||
Adding an abstract directive to an `NgModule` will cause an error.
|
||||
A directive must have a `selector` property defined in order to match some element in a template.
|
||||
|
||||
## When do I need a `@Directive()` decorator without a selector?
|
||||
|
||||
If you're using dependency injection, or any Angular-specific
|
||||
feature, such as `@HostBinding()`, `@ViewChild()`, or `@Input()`, you need a
|
||||
`@Directive()` or `@Component()` decorator.
|
||||
The decorator lets the compiler know to generate the correct
|
||||
instructions to create that class and any classes that extend it.
|
||||
If you don't want to use that base class as a directive directly, leave
|
||||
the selector blank. If you do want it to be usable independently,
|
||||
fill in the metadata as usual.
|
||||
|
||||
Classes that don't use Angular features don't need an Angular decorator.
|
||||
|
||||
## I'm a library author. Should I add the `@Directive()` decorator to base classes?
|
||||
|
||||
|
||||
As support for selectorless decorators is introduced in
|
||||
Angular version 9, if you want to support Angular version 8 and earlier, you
|
||||
shouldn't add a selectorless `@Directive()` decorator.
|
||||
You can either add `@Directive()` with a selector or
|
||||
add an explicit constructor to affected subclasses.
|
||||
|
Loading…
Reference in New Issue