5 lines
29 KiB
JSON
5 lines
29 KiB
JSON
{
|
|
"id": "guide/ivy-compatibility-examples",
|
|
"title": "Ivy compatibility examples",
|
|
"contents": "\n\n\n<div class=\"github-links\">\n <a href=\"https://github.com/angular/angular/edit/master/aio/content/guide/ivy-compatibility-examples.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=\"ivy-compatibility-examples\">Ivy compatibility examples<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#ivy-compatibility-examples\"><i class=\"material-icons\">link</i></a></h1>\n<p>This appendix is intended to provide more background on Ivy changes. Many of these examples list error messages you may see, so searching by error message might be a good idea if you are debugging.</p>\n<div class=\"alert is-critical\">\nNOTE: Most of these issues affect a small percentage of applications encountering unusual or rare edge cases.\n</div>\n<a id=\"content-children-descendants\"></a>\n<h2 id=\"contentchildren-queries-only-match-direct-children-by-default\">@ContentChildren queries only match direct children by default<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#contentchildren-queries-only-match-direct-children-by-default\"><i class=\"material-icons\">link</i></a></h2>\n<h3 id=\"basic-example-of-change\">Basic example of change<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#basic-example-of-change\"><i class=\"material-icons\">link</i></a></h3>\n<p>Let's say a component (<code>Comp</code>) has a <code>@<a href=\"api/core/ContentChildren\" class=\"code-anchor\">ContentChildren</a></code> query for <code>'foo'</code>:</p>\n<code-example language=\"html\">\n<comp>\n <div>\n <div #foo></div> <!-- matches in old runtime, not in new runtime -->\n </div>\n</comp>\n</code-example>\n<p>In the previous runtime, the <code><div></code> with <code>#foo</code> would match.\nWith Ivy, that <code><div></code> does not match because it is not a direct child of <code><comp></code>.</p>\n<h3 id=\"background\">Background<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#background\"><i class=\"material-icons\">link</i></a></h3>\n<p>By default, <code>@<a href=\"api/core/ContentChildren\" class=\"code-anchor\">ContentChildren</a></code> queries have the <code>descendants</code> flag set to <code>false</code>.</p>\n<p>In the previous rendering engine, \"descendants\" referred to \"descendant directives\".\nAn element could be a match as long as there were no other directives between the element and the requesting directive.\nThis made sense for directives with nesting like tabs, where nested tab directives might not be desirable to match.\nHowever, this caused surprising behavior for users because adding an unrelated directive like <code><a href=\"api/common/NgClass\" class=\"code-anchor\">ngClass</a></code> to a wrapper element could invalidate query results.</p>\n<p>For example, with the content query and template below, the last two <code>Tab</code> directives would not be matches:</p>\n<code-example>\n@<a href=\"api/core/ContentChildren\" class=\"code-anchor\">ContentChildren</a>(Tab, {descendants: false}) tabs: <a href=\"api/core/QueryList\" class=\"code-anchor\">QueryList</a><Tab>\n</code-example>\n<code-example>\n<tab-list>\n <div>\n <tab> One </tab> <!-- match (nested in element) -->\n </div>\n <tab> <!-- match (top level) -->\n <tab> A </tab> <!-- not a match (nested in tab) -->\n </tab>\n <div [<a href=\"api/common/NgClass\" class=\"code-anchor\">ngClass</a>]=\"classes\">\n <tab> Two </tab> <!-- not a match (nested in <a href=\"api/common/NgClass\" class=\"code-anchor\">ngClass</a>) -->\n </div>\n</tab-list>\n</code-example>\n<p>In addition, the differences between type and string predicates were subtle and sometimes unclear.\nFor example, if you replace the type predicate above with a <code>'foo'</code> string predicate, the matches change:</p>\n<code-example>\n@<a href=\"api/core/ContentChildren\" class=\"code-anchor\">ContentChildren</a>('foo', {descendants: false}) foos: <a href=\"api/core/QueryList\" class=\"code-anchor\">QueryList</a><<a href=\"api/core/ElementRef\" class=\"code-anchor\">ElementRef</a>>\n</code-example>\n<code-example>\n<tab-list>\n <div>\n <div #foo> One </div> <!-- match (nested in element) -->\n </div>\n <tab #foo> <!-- match (top level) -->\n <div #foo> A </div> <!-- match (nested in tab) -->\n </tab>\n <div [<a href=\"api/common/NgClass\" class=\"code-anchor\">ngClass</a>]=\"classes\">\n <div #foo> Two </div> <!-- match (nested in <a href=\"api/common/NgClass\" class=\"code-anchor\">ngClass</a>) -->\n </div>\n</tab-list>\n</code-example>\n<p>Because the previous behavior was inconsistent and surprising to users, we did not want to reproduce it in Ivy.\nInstead, we simplified the mental model so that \"descendants\" refers to DOM nesting only.\nAny DOM element between the requesting component and a potential match will invalidate that match.\nType predicates and string predicates also have identical matching behavior.</p>\n<p>Ivy behavior for directive/string predicates:</p>\n<code-example>\n<tab-list>\n <div>\n <tab> One </tab> <!-- not a match (nested in element) -->\n </div>\n <tab> <!-- match (top level) -->\n <tab> A </tab> <!-- not a match (nested in tab) -->\n </tab>\n <div [<a href=\"api/common/NgClass\" class=\"code-anchor\">ngClass</a>]=\"classes\">\n <tab> Two </tab> <!-- not a match (nested in div) -->\n </div>\n</tab-list>\n</code-example>\n<h3 id=\"example-of-error\">Example of error<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#example-of-error\"><i class=\"material-icons\">link</i></a></h3>\n<p>The error message that you see will depend on how the particular content query is used in the application code.\nFrequently, an error is thrown when a property is referenced on the content query result (which is now <code>undefined</code>).</p>\n<p>For example, if the component sets the content query results to a property, <code>foos</code>, <code>foos.first.bar</code> would throw the error:</p>\n<code-example>\nUncaught TypeError: Cannot read property 'bar' of undefined\n</code-example>\n<p>If you see an error like this, and the <code>undefined</code> property refers to the result of a <code>@<a href=\"api/core/ContentChildren\" class=\"code-anchor\">ContentChildren</a></code> query, it may well be caused by this change.</p>\n<h3 id=\"recommended-fix\">Recommended fix<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#recommended-fix\"><i class=\"material-icons\">link</i></a></h3>\n<p>You can either add the <code>descendants: true</code> flag to ignore wrapper elements or remove the wrapper elements themselves.</p>\n<p>Option 1:</p>\n<code-example>\n@<a href=\"api/core/ContentChildren\" class=\"code-anchor\">ContentChildren</a>('foo', {descendants: true}) foos: <a href=\"api/core/QueryList\" class=\"code-anchor\">QueryList</a><<a href=\"api/core/ElementRef\" class=\"code-anchor\">ElementRef</a>>;\n</code-example>\n<p>Option 2:</p>\n<code-example>\n<comp>\n <div #foo></div> <!-- matches in both old runtime and new runtime -->\n</comp>\n</code-example>\n<a id=\"undecorated-classes\"></a>\n<h2 id=\"all-classes-that-use-angular-di-must-have-an-angular-class-level-decorator\">All classes that use Angular DI must have an Angular class-level decorator<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#all-classes-that-use-angular-di-must-have-an-angular-class-level-decorator\"><i class=\"material-icons\">link</i></a></h2>\n<h3 id=\"basic-example-of-change-1\">Basic example of change:<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#basic-example-of-change-1\"><i class=\"material-icons\">link</i></a></h3>\n<p>In the previous rendering engine, the following would work:</p>\n<code-example>\nexport class DataService {\n constructor(@<a href=\"api/core/Inject\" class=\"code-anchor\">Inject</a>('CONFIG') public config: DataConfig) {}\n}\n\n@<a href=\"api/core/Injectable\" class=\"code-anchor\">Injectable</a>()\nexport class AppService extends DataService {...}\n</code-example>\n<p>In Ivy, it will throw an error because <code>DataService</code> is using Angular dependency injection, but is missing an <code>@<a href=\"api/core/Injectable\" class=\"code-anchor\">Injectable</a></code> decorator.</p>\n<p>The following would also work in the previous rendering engine, but in Ivy would require a <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a></code> decorator because it uses DI:</p>\n<code-example>\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>The same is true if your directive class extends a decorated directive, but does not have a decorator of its own.</p>\n<p>If you're using the CLI, there are two automated migrations that should transition your code for you (<a href=\"guide/migration-injectable\">this one</a> and <a href=\"guide/migration-undecorated-classes\">this one</a>).\nHowever, as you're adding new code in version 9, you may run into this difference.</p>\n<h3 id=\"background-1\">Background<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#background-1\"><i class=\"material-icons\">link</i></a></h3>\n<p>When a class has an Angular decorator like <code>@<a href=\"api/core/Injectable\" class=\"code-anchor\">Injectable</a></code> or <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a></code>, the Angular compiler generates extra code to support injecting dependencies into the constructor of your class.\nWhen using inheritance, Ivy needs both the parent class and the child class to apply a decorator to generate the correct code.\nOtherwise, 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, and Angular won't have the dependency info it needs to create it properly.</p>\n<p>In the previous rendering engine, the compiler had global knowledge, so in some cases (such as AOT mode or the presence of certain injection flags), it could look up the missing data.\nHowever, the Ivy compiler only processes each class in isolation.\nThis means that compilation has the potential to be faster (and opens the framework up for optimizations and features going forward), but the compiler can't automatically infer the same information as before.</p>\n<p>Adding the proper decorator explicitly provides this information.</p>\n<h3 id=\"example-of-error-1\">Example of error<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#example-of-error-1\"><i class=\"material-icons\">link</i></a></h3>\n<p>In JIT mode, the framework will throw the following error:</p>\n<code-example>\nERROR: This constructor is not compatible with Angular Dependency Injection because its dependency at index X of the parameter list is invalid.\nThis can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator.\n\nPlease check that 1) the type for the parameter at index X is correct and 2) the correct Angular decorators are defined for this class and its ancestors.\n</code-example>\n<p>In AOT mode, you'll see something like:</p>\n<code-example>\nX inherits its constructor from Y, but the latter does not have an Angular decorator of its own.\nDependency injection will not be able to resolve the parameters of Y's constructor. Either add a\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a> decorator to Y, or add an explicit constructor to X.\n</code-example>\n<p>In some cases, the framework may not be able to detect the missing decorator.\nIn these cases, you'll generally see a runtime error thrown when there is a property access attempted on the missing dependency.\nIf dependency was <code>foo</code>, you'd see an error when accessing something like <code>foo.bar</code>:</p>\n<code-example>\nUncaught TypeError: Cannot read property 'bar' of undefined\n</code-example>\n<p>If you see an error like this, and the <code>undefined</code> value refers to something that should have been injected, it may be this change.</p>\n<h3 id=\"recommended-fix-1\">Recommended fix<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#recommended-fix-1\"><i class=\"material-icons\">link</i></a></h3>\n<ul>\n<li>Add an <code>@<a href=\"api/core/Injectable\" class=\"code-anchor\">Injectable</a></code> decorator to anything you plan to provide or inject.</li>\n</ul>\n<code-example>\n@<a href=\"api/core/Injectable\" class=\"code-anchor\">Injectable</a>()\nexport class DataService {\n constructor(@<a href=\"api/core/Inject\" class=\"code-anchor\">Inject</a>('CONFIG') public config: DataConfig) {}\n}\n\n@<a href=\"api/core/Injectable\" class=\"code-anchor\">Injectable</a>()\nexport class AppService extends DataService {...}\n</code-example>\n<ul>\n<li>Add a <a href=\"guide/migration-undecorated-classes#what-does-it-mean-to-have-a-directive-decorator-with-no-metadata-inside-of-it\">selectorless <code>@Directive</code> decorator</a> to any class that extends a directive or any class from which a directive inherits.</li>\n</ul>\n<code-example>\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>() // selectorless, so it's not usable directly\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<a id=\"select-value-binding\"></a>\n<h2 id=\"cannot-bind-to-value-property-of-select-with-ngfor\">Cannot Bind to <code>value</code> property of <code><select></code> with <code>*<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a></code><a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#cannot-bind-to-value-property-of-select-with-ngfor\"><i class=\"material-icons\">link</i></a></h2>\n<h3 id=\"basic-example-of-change-2\">Basic example of change<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#basic-example-of-change-2\"><i class=\"material-icons\">link</i></a></h3>\n<code-example language=\"html\">\n<select [value]=\"someValue\">\n <option *<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a>=\"let option of options\" [value]=\"option\"> {{ option }} <option>\n</select>\n</code-example>\n<p>In the View Engine runtime, the above code would set the initial value of the <code><select></code> as expected.\nIn Ivy, the initial value would not be set at all in this case.</p>\n<h3 id=\"background-2\">Background<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#background-2\"><i class=\"material-icons\">link</i></a></h3>\n<p>Prior to Ivy, directive input bindings were always executed in their own change detection pass before any DOM bindings were processed.\nThis was an implementation detail that supported the use case in question:</p>\n<code-example language=\"html\">\n<select [value]=\"someValue\">\n <option *<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a>=\"let option of options\" [value]=\"option\"> {{ option }} <option>\n</select>\n</code-example>\n<p>It happened to work because the <code>*<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a></code> would be checked first, during the directive input binding pass, and thus create the options first.\nThen the DOM binding pass would run, which would check the <code>value</code> binding.\nAt this time, it would be able to match the value against one of the existing options, and set the value of the <code><select></code> element in the DOM to display that option.</p>\n<p>In Ivy, bindings are checked in the order they are defined in the template, regardless of whether they are directive input bindings or DOM bindings.\nThis change makes change detection easier to reason about for debugging purposes, since bindings will be checked in depth-first order as declared in the template.</p>\n<p>In this case, it means that the <code>value</code> binding will be checked before the <code>*<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a></code> is checked, as it is declared above the <code>*<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a></code> in the template.\nConsequently, the value of the <code><select></code> element will be set before any options are created, and it won't be able to match and display the correct option in the DOM.</p>\n<h3 id=\"example-of-error-2\">Example of error<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#example-of-error-2\"><i class=\"material-icons\">link</i></a></h3>\n<p>There is no error thrown, but the <code><select></code> in question will not have the correct initial value displayed in the DOM.</p>\n<h3 id=\"recommended-fix-2\">Recommended fix<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#recommended-fix-2\"><i class=\"material-icons\">link</i></a></h3>\n<p>To fix this problem, we recommend binding to the <code>selected</code> property on the <code><option></code> instead of the <code>value</code> on the <code><select></code>.</p>\n<p><em>Before</em></p>\n<code-example language=\"html\">\n<select [value]=\"someValue\">\n <option *<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a>=\"let option of options\" [value]=\"option\"> {{ option }} <option>\n</select>\n</code-example>\n<p><em>After</em></p>\n<code-example language=\"html\">\n<select>\n <option *<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a>=\"let option of options\" [value]=\"option\" [selected]=\"someValue == option\">\n {{ option }}\n <option>\n</select>\n</code-example>\n<a id=\"forward-refs-directive-inputs\"></a>\n<h2 id=\"forward-references-to-directive-inputs-accessed-through-local-refs-are-no-longer-supported\">Forward references to directive inputs accessed through local refs are no longer supported.<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#forward-references-to-directive-inputs-accessed-through-local-refs-are-no-longer-supported\"><i class=\"material-icons\">link</i></a></h2>\n<h3 id=\"basic-example-of-change-3\">Basic example of change<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#basic-example-of-change-3\"><i class=\"material-icons\">link</i></a></h3>\n<code-example language=\"ts\">\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>({\n selector: '[myDir]',\n exportAs: 'myDir'\n})\nexport class MyDir {\n @<a href=\"api/core/Input\" class=\"code-anchor\">Input</a>() message: string;\n}\n</code-example>\n<code-example language=\"html\">\n{{ myDir.name }}\n<div myDir #myDir=\"myDir\" [name]=\"myName\"></div>\n</code-example>\n<p>In the View Engine runtime, the above code would print out the name without any errors.\nIn Ivy, the <code>myDir.name</code> binding will throw an <code>ExpressionChangedAfterItHasBeenCheckedError</code>.</p>\n<h3 id=\"background-3\">Background<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#background-3\"><i class=\"material-icons\">link</i></a></h3>\n<p>In the ViewEngine runtime, directive input bindings and element bindings were executed in different stages. Angular would process the template one full time to check directive inputs only (e.g. <code>[name]</code>), then process the whole template again to check element and text bindings only (e.g.<code>{{ myDir.name }}</code>). This meant that the <code>name</code> directive input would be checked before the <code>myDir.name</code> text binding despite their relative order in the template, which some users felt to be counterintuitive.</p>\n<p>In contrast, Ivy processes the template in just one pass, so that bindings are checked in the same order that they are written in the template. In this case, it means that the <code>myDir.name</code> binding will be checked before the <code>name</code> input sets the property on the directive (and thus it will be <code>undefined</code>). Since the <code>myDir.name</code> property will be set by the time the next change detection pass runs, a change detection error is thrown.</p>\n<h3 id=\"example-of-error-3\">Example of error<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#example-of-error-3\"><i class=\"material-icons\">link</i></a></h3>\n<p>Assuming that the value for <code>myName</code> is <code>Angular</code>, you should see an error that looks like</p>\n<code-example>\nError: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: 'Angular'.\n</code-example>\n<h3 id=\"recommended-fix-3\">Recommended fix<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#recommended-fix-3\"><i class=\"material-icons\">link</i></a></h3>\n<p>To fix this problem, we recommend either getting the information for the binding directly from the host component (e.g. the <code>myName</code> property from our example) or to move the data binding after the directive has been declared so that the initial value is available on the first pass.</p>\n<p><em>Before</em></p>\n<code-example language=\"html\">\n{{ myDir.name }}\n<div myDir #myDir=\"myDir\" [name]=\"myName\"></div>\n</code-example>\n<p><em>After</em></p>\n<code-example language=\"html\">\n{{ myName }}\n<div myDir [name]=\"myName\"></div>\n</code-example>\n<a id=\"foreign-values\"></a>\n<h2 id=\"foreign-functions-and-foreign-values-arent-statically-resolvable\">Foreign functions and foreign values aren't statically resolvable<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#foreign-functions-and-foreign-values-arent-statically-resolvable\"><i class=\"material-icons\">link</i></a></h2>\n<h3 id=\"basic-example-of-change-4\">Basic example of change<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#basic-example-of-change-4\"><i class=\"material-icons\">link</i></a></h3>\n<p>Consider a library that defines and exports some selector string to be used in other libraries:</p>\n<code-example>\nexport let mySelector = '[my-selector]';\n</code-example>\n<p>This selector is then imported in another library or an application:</p>\n<code-example>\nimport {mySelector} from 'my-library';\n\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>({selector: mySelector})\nexport class MyDirective {}\n</code-example>\n<p>Because the <code>mySelector</code> value is imported from an external library, it is part of a different compilation unit and therefore considered <em>foreign</em>.</p>\n<p>While this code would work correctly in the View Engine compiler, it would fail to compile in Ivy in AOT mode.</p>\n<h3 id=\"background-4\">Background<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#background-4\"><i class=\"material-icons\">link</i></a></h3>\n<p>In View Engine, the compiler would capture the source code of a library in <code>metadata.json</code> files when bundling the library, so that external consumers could \"look inside\" the source code of an external library.\nWhen AOT-compiling the application, the <code>metadata.json</code> files would be used to determine the value of <code>mySelector</code>.\nIn Ivy, the <code>metadata.json</code> files are no longer used. Instead, the compiler extracts metadata for external libraries from the <code>.d.ts</code> files that TypeScript creates.\nThis has several benefits such as better performance, much improved error reporting, and enables more build caching opportunities as there is no longer a dependency on library internals.</p>\n<p>Looking back at the previous example, the <code>mySelector</code> value would be represented in the <code>.d.ts</code> as follows:</p>\n<code-example>\nexport declare let mySelector: string;\n</code-example>\n<p>Notice that the actual value of the selector is no longer present, so that the Ivy compiler is unable to use it during AOT compilations.</p>\n<h3 id=\"example-of-error-4\">Example of error<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#example-of-error-4\"><i class=\"material-icons\">link</i></a></h3>\n<p>In the above example, a compilation error would occur when compiling <code>MyDirective</code>:</p>\n<code-example>\nerror NG1010: selector must be a string\n Value is a reference to 'mySelector'.\n\n 1 export declare let mySelector: string;\n ~~~~~~~~~~\n Reference is declared here.\n</code-example>\n<h3 id=\"recommended-fix-4\">Recommended fix<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/ivy-compatibility-examples#recommended-fix-4\"><i class=\"material-icons\">link</i></a></h3>\n<p>When exporting values from a library, ensure the actual value is present in the <code>.d.ts</code> file. This typically requires that the variable be declared as a constant:</p>\n<code-example>\nexport const mySelector = '[my-selector]';\n</code-example>\n<p>In classes, a field should be declared using the <code><a href=\"api/upgrade/static\" class=\"code-anchor\">static</a> readonly</code> modifiers:</p>\n<code-example>\nexport class Selectors {\n <a href=\"api/upgrade/static\" class=\"code-anchor\">static</a> readonly mySelector = '[my-selector]';\n}\n</code-example>\n\n \n</div>\n\n<!-- links to this doc:\n - guide/ivy-compatibility\n-->\n<!-- links from this doc:\n - api/common/NgClass\n - api/common/NgForOf\n - api/core/ContentChildren\n - api/core/Directive\n - api/core/ElementRef\n - api/core/Inject\n - api/core/Injectable\n - api/core/Input\n - api/core/QueryList\n - api/core/ViewContainerRef\n - api/upgrade/static\n - guide/ivy-compatibility-examples#all-classes-that-use-angular-di-must-have-an-angular-class-level-decorator\n - guide/ivy-compatibility-examples#background\n - guide/ivy-compatibility-examples#background-1\n - guide/ivy-compatibility-examples#background-2\n - guide/ivy-compatibility-examples#background-3\n - guide/ivy-compatibility-examples#background-4\n - guide/ivy-compatibility-examples#basic-example-of-change\n - guide/ivy-compatibility-examples#basic-example-of-change-1\n - guide/ivy-compatibility-examples#basic-example-of-change-2\n - guide/ivy-compatibility-examples#basic-example-of-change-3\n - guide/ivy-compatibility-examples#basic-example-of-change-4\n - guide/ivy-compatibility-examples#cannot-bind-to-value-property-of-select-with-ngfor\n - guide/ivy-compatibility-examples#contentchildren-queries-only-match-direct-children-by-default\n - guide/ivy-compatibility-examples#example-of-error\n - guide/ivy-compatibility-examples#example-of-error-1\n - guide/ivy-compatibility-examples#example-of-error-2\n - guide/ivy-compatibility-examples#example-of-error-3\n - guide/ivy-compatibility-examples#example-of-error-4\n - guide/ivy-compatibility-examples#foreign-functions-and-foreign-values-arent-statically-resolvable\n - guide/ivy-compatibility-examples#forward-references-to-directive-inputs-accessed-through-local-refs-are-no-longer-supported\n - guide/ivy-compatibility-examples#ivy-compatibility-examples\n - guide/ivy-compatibility-examples#recommended-fix\n - guide/ivy-compatibility-examples#recommended-fix-1\n - guide/ivy-compatibility-examples#recommended-fix-2\n - guide/ivy-compatibility-examples#recommended-fix-3\n - guide/ivy-compatibility-examples#recommended-fix-4\n - guide/migration-injectable\n - guide/migration-undecorated-classes\n - guide/migration-undecorated-classes#what-does-it-mean-to-have-a-directive-decorator-with-no-metadata-inside-of-it\n - https://github.com/angular/angular/edit/master/aio/content/guide/ivy-compatibility-examples.md?message=docs%3A%20describe%20your%20change...\n-->"
|
|
} |