angular-cn/aio/dist/generated/docs/guide/migration-undecorated-classes.json

5 lines
16 KiB
JSON

{
"id": "guide/migration-undecorated-classes",
"title": "Missing @Directive()/@Component() decorator migration",
"contents": "\n\n\n<div class=\"github-links\">\n <a href=\"https://github.com/angular/angular/edit/master/aio/content/guide/migration-undecorated-classes.md?message=docs%3A%20describe%20your%20change...\" aria-label=\"Suggest Edits\" title=\"Suggest Edits\"><i class=\"material-icons\" aria-hidden=\"true\" role=\"img\">mode_edit</i></a>\n</div>\n\n\n<div class=\"content\">\n <h1 id=\"missing-directivecomponent-decorator-migration\">Missing <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>()</code>/<code>@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>()</code> decorator migration<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/migration-undecorated-classes#missing-directivecomponent-decorator-migration\"><i class=\"material-icons\">link</i></a></h1>\n<h2 id=\"what-does-this-migration-do\">What does this migration do?<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/migration-undecorated-classes#what-does-this-migration-do\"><i class=\"material-icons\">link</i></a></h2>\n<p>This migration adds an empty <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>()</code> decorator to undecorated\nbase classes that:</p>\n<ul>\n<li>use Angular features</li>\n<li>are extended by directives or components</li>\n</ul>\n<p>For example, in the diff below, a <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>()</code> decorator is added to <code>BaseMenu</code> because <code>BaseMenu</code> uses dependency injection.</p>\n<p> <strong>Before:</strong></p>\n<code-example language=\"ts\">\nexport class BaseMenu {\n constructor(private vcr: <a href=\"api/core/ViewContainerRef\" class=\"code-anchor\">ViewContainerRef</a>) {}\n}\n\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>({selector: '[settingsMenu]'})\nexport class SettingsMenu extends BaseMenu {}\n</code-example>\n<p> <strong>After:</strong></p>\n<code-example language=\"ts\">\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>()\nexport class BaseMenu {\n constructor(private vcr: <a href=\"api/core/ViewContainerRef\" class=\"code-anchor\">ViewContainerRef</a>) {}\n}\n\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>({selector: '[settingsMenu]'})\nexport class SettingsMenu extends BaseMenu {}\n</code-example>\n<p>In the event that a directive or component is extended by a class without a decorator, the schematic copies any inherited directive or component metadata to the derived class.</p>\n<p><strong>Before:</strong></p>\n<code-example language=\"ts\">\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'base-menu',\n template: '&#x3C;div>&#x3C;/div>'\n})\nclass BaseMenu {}\n\nexport class SettingsMenu extends BaseMenu {}\n</code-example>\n<p><strong>After:</strong></p>\n<code-example language=\"ts\">\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'base-menu',\n template: '&#x3C;div>&#x3C;/div>'\n})\nclass BaseMenu {}\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'base-menu',\n template: '&#x3C;div>&#x3C;/div>'\n})\nexport class SettingsMenu extends BaseMenu {}\n</code-example>\n<p>This schematic also decorates classes that use Angular field decorators, including:</p>\n<ul>\n<li><code>@<a href=\"api/core/Input\" class=\"code-anchor\">Input</a>()</code></li>\n<li><code>@<a href=\"api/core/Output\" class=\"code-anchor\">Output</a>()</code></li>\n<li><code>@<a href=\"api/core/HostBinding\" class=\"code-anchor\">HostBinding</a>()</code></li>\n<li><code>@<a href=\"api/core/HostListener\" class=\"code-anchor\">HostListener</a>()</code></li>\n<li><code>@<a href=\"api/core/ViewChild\" class=\"code-anchor\">ViewChild</a>()</code> / <code>@<a href=\"api/core/ViewChildren\" class=\"code-anchor\">ViewChildren</a>()</code></li>\n<li><code>@<a href=\"api/core/ContentChild\" class=\"code-anchor\">ContentChild</a>()</code> / <code>@<a href=\"api/core/ContentChildren\" class=\"code-anchor\">ContentChildren</a>()</code></li>\n</ul>\n<p><strong>Before:</strong></p>\n<code-example language=\"ts\">\nclass Base {\n @<a href=\"api/core/Output\" class=\"code-anchor\">Output</a>()\n countChanged = new <a href=\"api/core/EventEmitter\" class=\"code-anchor\">EventEmitter</a>&#x3C;number>();\n}\n\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>({\n selector: '[myDir]'\n})\nclass Dir extends Base {\n}\n</code-example>\n<p><strong>After:</strong></p>\n<code-example language=\"ts\">\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>() // schematic adds @<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>()\nclass Base {\n @<a href=\"api/core/Output\" class=\"code-anchor\">Output</a>()\n countChanged = new <a href=\"api/core/EventEmitter\" class=\"code-anchor\">EventEmitter</a>&#x3C;number>();\n}\n\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>({\n selector: '[myDir]'\n})\nclass Dir extends Base {\n}\n</code-example>\n<h2 id=\"why-is-this-migration-necessary\">Why is this migration necessary?<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/migration-undecorated-classes#why-is-this-migration-necessary\"><i class=\"material-icons\">link</i></a></h2>\n<h3 id=\"migrating-classes-that-use-di\">Migrating classes that use DI<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/migration-undecorated-classes#migrating-classes-that-use-di\"><i class=\"material-icons\">link</i></a></h3>\n<p>When a class has a <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>()</code> or <code>@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>()</code> decorator, the Angular compiler generates extra code to inject dependencies into the constructor.\nWhen using inheritance, Ivy needs both the parent class and the child class to apply a decorator to generate the correct code.</p>\n<p>You can think of this change as two cases: a parent class is missing a\ndecorator or a child class is missing a decorator.\nIn both scenarios, Angular's runtime needs additional information from the compiler.\nThis additional information comes from adding decorators.</p>\n<h4 id=\"decorator-missing-from-parent-class\">Decorator missing from parent class<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/migration-undecorated-classes#decorator-missing-from-parent-class\"><i class=\"material-icons\">link</i></a></h4>\n<p>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).\nWhen Angular then tries to create the subclass, it doesn't have the correct info to create it.</p>\n<p>In View Engine, the compiler has global knowledge, so it can look up the missing data.\nHowever, the Ivy compiler only processes each directive in isolation.\nThis means that compilation can be faster, but the compiler can't automatically infer the same information as before.\nAdding the <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>()</code> explicitly provides this information.</p>\n<p>In the future, add <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>()</code> to base classes that do not already have decorators and are extended by directives.</p>\n<h4 id=\"decorator-missing-from-child-class\">Decorator missing from child class<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/migration-undecorated-classes#decorator-missing-from-child-class\"><i class=\"material-icons\">link</i></a></h4>\n<p>When the child class is missing the decorator, the child class inherits from the parent class yet has no decorators of its own.\nWithout a decorator, the compiler has no way of knowing that the class is a <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a></code> or <code>@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a></code>, so it doesn't generate the proper instructions for the directive.</p>\n<h3 id=\"migrating-classes-that-use-field-decorators\">Migrating classes that use field decorators<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/migration-undecorated-classes#migrating-classes-that-use-field-decorators\"><i class=\"material-icons\">link</i></a></h3>\n<p>In ViewEngine, base classes with field decorators like <code>@<a href=\"api/core/Input\" class=\"code-anchor\">Input</a>()</code> worked even when the class did not have a <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>()</code> or <code>@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>()</code> decorator.\nFor example:</p>\n<code-example language=\"ts\">\nclass Base {\n @<a href=\"api/core/Input\" class=\"code-anchor\">Input</a>()\n foo: string;\n}\n\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>(...)\nclass Dir extends Base {\n ngOnChanges(): void {\n // notified when bindings to [foo] are updated\n }\n}\n</code-example>\n<p>However, this example won't compile with Ivy because the <code>Base</code> class <em>requires</em> either a <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>()</code> or <code>@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>()</code> decorator to generate code for inputs, outputs, queries, and host bindings.</p>\n<p>Always requiring a class decorator leads to two main benefits for Angular:</p>\n<ol>\n<li>\n<p>The previous behavior was inconsistent.\nSome Angular features required a decorator (dependency injection), but others did not.\nNow, all Angular features consistently require a class decorator.</p>\n</li>\n<li>\n<p>Supporting undecorated classes increases the code size and complexity of Angular.\nAlways requiring class decorators allows the framework to become smaller and simpler for all users.</p>\n</li>\n</ol>\n<h2 id=\"what-does-it-mean-to-have-a-directive-decorator-with-no-metadata-inside-of-it\">What does it mean to have a <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>()</code> decorator with no metadata inside of it?<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/migration-undecorated-classes#what-does-it-mean-to-have-a-directive-decorator-with-no-metadata-inside-of-it\"><i class=\"material-icons\">link</i></a></h2>\n<p>The presence of the <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a></code> decorator causes Angular to generate extra code for the affected class.\nIf that decorator includes no properties (metadata), the directive won't be matched to elements or instantiated directly, but other classes that <em>extend</em> the directive class will inherit this generated code.\nYou can think of this as an \"abstract\" directive.</p>\n<p>Adding an abstract directive to an <code><a href=\"api/core/NgModule\" class=\"code-anchor\">NgModule</a></code> will cause an error.\nA directive must have a <code>selector</code> property defined in order to match some element in a template.</p>\n<h2 id=\"when-do-i-need-a-directive-decorator-without-a-selector\">When do I need a <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>()</code> decorator without a selector?<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/migration-undecorated-classes#when-do-i-need-a-directive-decorator-without-a-selector\"><i class=\"material-icons\">link</i></a></h2>\n<p>If you're using dependency injection, or any Angular-specific feature, such as <code>@<a href=\"api/core/HostBinding\" class=\"code-anchor\">HostBinding</a>()</code>, <code>@<a href=\"api/core/ViewChild\" class=\"code-anchor\">ViewChild</a>()</code>, or <code>@<a href=\"api/core/Input\" class=\"code-anchor\">Input</a>()</code>, you need a <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>()</code> or <code>@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>()</code> decorator.\nThe decorator lets the compiler know to generate the correct instructions to create that class and any classes that extend it.\nIf you don't want to use that base class as a directive directly, leave the selector blank.\nIf you do want it to be usable independently, fill in the metadata as usual.</p>\n<p>Classes that don't use Angular features don't need an Angular decorator.</p>\n<h2 id=\"im-a-library-author-should-i-add-the-directive-decorator-to-base-classes\">I'm a library author. Should I add the <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>()</code> decorator to base classes?<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/migration-undecorated-classes#im-a-library-author-should-i-add-the-directive-decorator-to-base-classes\"><i class=\"material-icons\">link</i></a></h2>\n<p>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 <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>()</code> decorator.\nYou can either add <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>()</code> with a selector or move the Angular-specific features to affected subclasses.</p>\n<h2 id=\"what-about-applications-using-non-migrated-libraries\">What about applications using non-migrated libraries?<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/migration-undecorated-classes#what-about-applications-using-non-migrated-libraries\"><i class=\"material-icons\">link</i></a></h2>\n<p>The <a href=\"guide/glossary#ngcc\">Angular compatibility compiler</a> (<code>ngcc</code>) should automatically transform any non-migrated libraries to generate the proper code.</p>\n\n \n</div>\n\n<!-- links to this doc:\n - guide/ivy-compatibility-examples\n-->\n<!-- links from this doc:\n - api/core/Component\n - api/core/ContentChild\n - api/core/ContentChildren\n - api/core/Directive\n - api/core/EventEmitter\n - api/core/HostBinding\n - api/core/HostListener\n - api/core/Input\n - api/core/NgModule\n - api/core/Output\n - api/core/ViewChild\n - api/core/ViewChildren\n - api/core/ViewContainerRef\n - guide/glossary#ngcc\n - guide/migration-undecorated-classes#decorator-missing-from-child-class\n - guide/migration-undecorated-classes#decorator-missing-from-parent-class\n - guide/migration-undecorated-classes#im-a-library-author-should-i-add-the-directive-decorator-to-base-classes\n - guide/migration-undecorated-classes#migrating-classes-that-use-di\n - guide/migration-undecorated-classes#migrating-classes-that-use-field-decorators\n - guide/migration-undecorated-classes#missing-directivecomponent-decorator-migration\n - guide/migration-undecorated-classes#what-about-applications-using-non-migrated-libraries\n - guide/migration-undecorated-classes#what-does-it-mean-to-have-a-directive-decorator-with-no-metadata-inside-of-it\n - guide/migration-undecorated-classes#what-does-this-migration-do\n - guide/migration-undecorated-classes#when-do-i-need-a-directive-decorator-without-a-selector\n - guide/migration-undecorated-classes#why-is-this-migration-necessary\n - https://github.com/angular/angular/edit/master/aio/content/guide/migration-undecorated-classes.md?message=docs%3A%20describe%20your%20change...\n-->"
}