5 lines
29 KiB
JSON
5 lines
29 KiB
JSON
{
|
||
"id": "guide/structural-directives",
|
||
"title": "Writing structural directives",
|
||
"contents": "\n\n\n<div class=\"github-links\">\n <a href=\"https://github.com/angular/angular/edit/master/aio/content/guide/structural-directives.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=\"writing-structural-directives\">Writing structural directives<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/structural-directives#writing-structural-directives\"><i class=\"material-icons\">link</i></a></h1>\n<p>This topic demonstrates how to create a structural directive and provides conceptual information on how directives work, how Angular interprets shorthand, and how to add template guard properties to catch template type errors.</p>\n<div class=\"alert is-helpful\">\n<p>For the example app that this page describes, see the <live-example></live-example>.</p>\n</div>\n<p>For more information on Angular's built-in structural directives, such as <code><a href=\"api/common/NgIf\" class=\"code-anchor\">NgIf</a></code>, <code>NgFor</code>, and <code><a href=\"api/common/NgSwitch\" class=\"code-anchor\">NgSwitch</a></code>, see <a href=\"guide/built-in-directives\">Built-in directives</a>.</p>\n<a id=\"unless\"></a>\n<h2 id=\"creating-a-structural-directive\">Creating a structural directive<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/structural-directives#creating-a-structural-directive\"><i class=\"material-icons\">link</i></a></h2>\n<p>This section guides you through creating an <code>UnlessDirective</code> and how to set <code>condition</code> values.\nThe <code>UnlessDirective</code> does the opposite of <code><a href=\"api/common/NgIf\" class=\"code-anchor\">NgIf</a></code>, and <code>condition</code> values can be set to <code>true</code> or <code>false</code>.\n<code><a href=\"api/common/NgIf\" class=\"code-anchor\">NgIf</a></code> displays the template content when the condition is <code>true</code>.\n<code>UnlessDirective</code> displays the content when the condition is <code>false</code>.</p>\n<p>Following is the <code>UnlessDirective</code> selector, <code>appUnless</code>, applied to the paragraph element.\nWhen <code>condition</code> is <code>true</code>, the browser displays the sentence.</p>\n<code-example path=\"structural-directives/src/app/app.component.html\" header=\"src/app/app.component.html (appUnless-1)\" region=\"appUnless-1\">\n<p *appUnless=\"condition\">Show this sentence unless the condition is true.</p>\n\n</code-example>\n<ol>\n<li>\n<p>Using the Angular CLI, run the following command, where <code>unless</code> is the name of the directive:</p>\n<code-example language=\"bash\">\nng generate directive unless\n</code-example>\n<p>Angular creates the directive class and specifies the CSS selector, <code>appUnless</code>, that identifies the directive in a template.</p>\n</li>\n<li>\n<p>Import <code><a href=\"api/core/Input\" class=\"code-anchor\">Input</a></code>, <code><a href=\"api/core/TemplateRef\" class=\"code-anchor\">TemplateRef</a></code>, and <code><a href=\"api/core/ViewContainerRef\" class=\"code-anchor\">ViewContainerRef</a></code>.</p>\n<code-example path=\"structural-directives/src/app/unless.directive.ts\" header=\"src/app/unless.directive.ts (skeleton)\" region=\"skeleton\">\nimport { <a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>, <a href=\"api/core/Input\" class=\"code-anchor\">Input</a>, <a href=\"api/core/TemplateRef\" class=\"code-anchor\">TemplateRef</a>, <a href=\"api/core/ViewContainerRef\" class=\"code-anchor\">ViewContainerRef</a> } from '@angular/core';\n\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>({ selector: '[appUnless]'})\nexport class UnlessDirective {\n}\n\n\n</code-example>\n</li>\n<li>\n<p>Inject <code><a href=\"api/core/TemplateRef\" class=\"code-anchor\">TemplateRef</a></code> and <code><a href=\"api/core/ViewContainerRef\" class=\"code-anchor\">ViewContainerRef</a></code> in the directive constructor as private variables.</p>\n<code-example path=\"structural-directives/src/app/unless.directive.ts\" header=\"src/app/unless.directive.ts (ctor)\" region=\"ctor\">\nconstructor(\n private templateRef: <a href=\"api/core/TemplateRef\" class=\"code-anchor\">TemplateRef</a><any>,\n private viewContainer: <a href=\"api/core/ViewContainerRef\" class=\"code-anchor\">ViewContainerRef</a>) { }\n\n</code-example>\n<p>The <code>UnlessDirective</code> creates an <a href=\"api/core/EmbeddedViewRef\" title=\"API: EmbeddedViewRef\">embedded view</a> from the Angular-generated <code><ng-template></code> and inserts that view in a <a href=\"api/core/ViewContainerRef\" title=\"API: ViewContainerRef\">view container</a> adjacent to the directive's original <code><p></code> host element.</p>\n<p><a href=\"api/core/TemplateRef\" title=\"API: TemplateRef\"><code>TemplateRef</code></a> helps you get to the <code><ng-template></code> contents and <a href=\"api/core/ViewContainerRef\" title=\"API: ViewContainerRef\"><code>ViewContainerRef</code></a> accesses the view container.</p>\n</li>\n<li>\n<p>Add an <code>appUnless</code> <code>@<a href=\"api/core/Input\" class=\"code-anchor\">Input</a>()</code> property with a setter.</p>\n<code-example path=\"structural-directives/src/app/unless.directive.ts\" header=\"src/app/unless.directive.ts (set)\" region=\"set\">\n@<a href=\"api/core/Input\" class=\"code-anchor\">Input</a>() set appUnless(condition: boolean) {\n if (!condition && !this.hasView) {\n this.viewContainer.createEmbeddedView(this.templateRef);\n this.hasView = true;\n } else if (condition && this.hasView) {\n this.viewContainer.clear();\n this.hasView = false;\n }\n}\n\n</code-example>\n<p>Angular sets the <code>appUnless</code> property whenever the value of the condition changes.</p>\n<ul>\n<li>\n<p>If the condition is falsy and Angular hasn't created the view previously, the setter causes the view container to create the embedded view from the template.</p>\n</li>\n<li>\n<p>If the condition is truthy and the view is currently displayed, the setter clears the container, which disposes of the view.</p>\n</li>\n</ul>\n</li>\n</ol>\n<p>The complete directive is as follows:</p>\n<code-example path=\"structural-directives/src/app/unless.directive.ts\" header=\"src/app/unless.directive.ts (excerpt)\" region=\"no-docs\">\nimport { <a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>, <a href=\"api/core/Input\" class=\"code-anchor\">Input</a>, <a href=\"api/core/TemplateRef\" class=\"code-anchor\">TemplateRef</a>, <a href=\"api/core/ViewContainerRef\" class=\"code-anchor\">ViewContainerRef</a> } from '@angular/core';\n\n/**\n * Add the template content to the DOM unless the condition is true.\n */\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>({ selector: '[appUnless]'})\nexport class UnlessDirective {\n private hasView = false;\n\n constructor(\n private templateRef: <a href=\"api/core/TemplateRef\" class=\"code-anchor\">TemplateRef</a><any>,\n private viewContainer: <a href=\"api/core/ViewContainerRef\" class=\"code-anchor\">ViewContainerRef</a>) { }\n\n @<a href=\"api/core/Input\" class=\"code-anchor\">Input</a>() set appUnless(condition: boolean) {\n if (!condition && !this.hasView) {\n this.viewContainer.createEmbeddedView(this.templateRef);\n this.hasView = true;\n } else if (condition && this.hasView) {\n this.viewContainer.clear();\n this.hasView = false;\n }\n }\n}\n\n\n</code-example>\n<h3 id=\"testing-the-directive\">Testing the directive<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/structural-directives#testing-the-directive\"><i class=\"material-icons\">link</i></a></h3>\n<p>In this section, you'll update your application to test the <code>UnlessDirective</code>.</p>\n<ol>\n<li>\n<p>Add a <code>condition</code> set to <code>false</code> in the <code>AppComponent</code>.</p>\n<code-example path=\"structural-directives/src/app/app.component.ts\" header=\"src/app/app.component.ts (excerpt)\" region=\"condition\">\ncondition = false;\n\n</code-example>\n</li>\n<li>\n<p>Update the template to use the directive.\nHere, <code>*appUnless</code> is on two <code><p></code> tags with opposite <code>condition</code> values, one <code>true</code> and one <code>false</code>.</p>\n<code-example path=\"structural-directives/src/app/app.component.html\" header=\"src/app/app.component.html (appUnless)\" region=\"appUnless\">\n<p *appUnless=\"condition\" class=\"unless a\">\n (A) This paragraph is displayed because the condition is false.\n</p>\n\n<p *appUnless=\"!condition\" class=\"unless b\">\n (B) Although the condition is true,\n this paragraph is displayed because appUnless is set to false.\n</p>\n\n</code-example>\n<p>The asterisk is shorthand that marks <code>appUnless</code> as a structural directive.\nWhen the <code>condition</code> is falsy, the top (A) paragraph appears and the bottom (B) paragraph disappears.\nWhen the <code>condition</code> is truthy, the top (A) paragraph disappears and the bottom (B) paragraph appears.</p>\n</li>\n<li>\n<p>To change and display the value of <code>condition</code> in the browser, add markup that displays the status and a button.</p>\n<code-example path=\"structural-directives/src/app/app.component.html\" header=\"src/app/app.component.html\" region=\"toggle-info\">\n<p>\n The condition is currently\n <span [<a href=\"api/common/NgClass\" class=\"code-anchor\">ngClass</a>]=\"{ 'a': !condition, 'b': condition, 'unless': true }\">{{condition}}</span>.\n <button\n (click)=\"condition = !condition\"\n [<a href=\"api/common/NgClass\" class=\"code-anchor\">ngClass</a>] = \"{ 'a': condition, 'b': !condition }\" >\n Toggle condition to {{condition ? 'false' : 'true'}}\n </button>\n</p>\n\n</code-example>\n</li>\n</ol>\n<p>To verify that the directive works, click the button to change the value of <code>condition</code>.</p>\n <div class=\"lightbox\">\n <img src=\"generated/images/guide/structural-directives/unless-anim.gif\" alt=\"UnlessDirective in action\" width=\"524\" height=\"100\">\n </div>\n<a id=\"shorthand\"></a>\n<a id=\"asterisk\"></a>\n<h2 id=\"structural-directive-shorthand\">Structural directive shorthand<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/structural-directives#structural-directive-shorthand\"><i class=\"material-icons\">link</i></a></h2>\n<p>The asterisk, <code>*</code>, syntax on a structural directive, such as <code>*<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a></code>, is shorthand that Angular interprets into a longer form.\nAngular transforms the asterisk in front of a structural directive into an <code><ng-template></code> that surrounds the host element and its descendants.</p>\n<p>The following is an example of <code>*<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a></code> that displays the hero's name if <code>hero</code> exists:</p>\n<code-example path=\"structural-directives/src/app/app.component.html\" header=\"src/app/app.component.html (asterisk)\" region=\"asterisk\">\n<div *<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>=\"hero\" class=\"name\">{{hero.name}}</div>\n\n</code-example>\n<p>The <code>*<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a></code> directive moves to the <code><ng-template></code> where it becomes a property binding in square brackets, <code>[<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>]</code>.\nThe rest of the <code><div></code>, including its class attribute, moves inside the <code><ng-template></code>.</p>\n<code-example path=\"structural-directives/src/app/app.component.html\" header=\"src/app/app.component.html (ngif-template)\" region=\"ngif-template\">\n<ng-template [<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>]=\"hero\">\n <div class=\"name\">{{hero.name}}</div>\n</ng-template>\n\n</code-example>\n<p>Angular does not create a real <code><ng-template></code> element, instead rendering only the <code><div></code> and a comment node placeholder to the DOM.</p>\n<code-example language=\"html\">\n<!--bindings={\n \"ng-reflect-ng-if\": \"[object Object]\"\n}-->\n<div _ngcontent-c0>Mr. Nice</div>\n</code-example>\n<p>The following example compares the shorthand use of the asterisk in <code>*<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a></code> with the longhand <code><ng-template></code> form:</p>\n<code-example path=\"structural-directives/src/app/app.component.html\" header=\"src/app/app.component.html (inside-ngfor)\" region=\"inside-ngfor\">\n<div *<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a>=\"let hero of heroes; let i=index; let odd=odd; trackBy: trackById\" [class.odd]=\"odd\">\n ({{i}}) {{hero.name}}\n</div>\n\n<ng-template <a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a> let-hero [<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngForOf</a>]=\"heroes\" let-i=\"index\" let-odd=\"odd\" [ngForTrackBy]=\"trackById\">\n <div [class.odd]=\"odd\">({{i}}) {{hero.name}}</div>\n</ng-template>\n\n</code-example>\n<p>Here, everything related to the <code><a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a></code> structural directive applies to the <code><ng-template></code>.\nAll other bindings and attributes on the element apply to the <code><div></code> element within the <code><ng-template></code>.\nOther modifiers on the host element, in addition to the <code><a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a></code> string, remain in place as the element moves inside the <code><ng-template></code>.\nIn this example, the <code>[class.odd]=\"odd\"</code> stays on the <code><div></code>.</p>\n<p>The <code>let</code> keyword declares a template input variable that you can reference within the template.\nThe input variables in this example are <code>hero</code>, <code>i</code>, and <code>odd</code>.\nThe parser translates <code>let hero</code>, <code>let i</code>, and <code>let odd</code> into variables named <code>let-hero</code>, <code>let-i</code>, and <code>let-odd</code>.\nThe <code>let-i</code> and <code>let-odd</code> variables become <code>let i=index</code> and <code>let odd=odd</code>.\nAngular sets <code>i</code> and <code>odd</code> to the current value of the context's <code>index</code> and <code>odd</code> properties.</p>\n<p>The parser applies PascalCase to all directives and prefixes them with the directive's attribute name, such as ngFor.\nFor example, the <code><a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a></code> input properties, <code>of</code> and <code>trackBy</code>, map to <code><a href=\"api/common/NgForOf\" class=\"code-anchor\">ngForOf</a></code> and <code>ngForTrackBy</code>.\nAs the <code>NgFor</code> directive loops through the list, it sets and resets properties of its own context object.\nThese properties can include, but aren't limited to, <code>index</code>, <code>odd</code>, and a special property\nnamed <code>$implicit</code>.</p>\n<p>Angular sets <code>let-hero</code> to the value of the context's <code>$implicit</code> property, which <code>NgFor</code> has initialized with the hero for the current iteration.</p>\n<p>For more information, see the <a href=\"api/common/NgForOf\" title=\"API: NgFor\">NgFor API</a> and <a href=\"api/common/NgForOf\">NgForOf API</a> documentation.</p>\n<h3 id=\"creating-template-fragments-with-ng-template\">Creating template fragments with <code><ng-template></code><a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/structural-directives#creating-template-fragments-with-ng-template\"><i class=\"material-icons\">link</i></a></h3>\n<p>Angular's <code><ng-template></code> element defines a template that doesn't render anything by default.\nWith <code><ng-template></code>, you can render the content manually for full control over how the content displays.</p>\n<p>If there is no structural directive and you wrap some elements in an <code><ng-template></code>, those elements disappear.\nIn the following example, Angular does not render the middle \"Hip!\" in the phrase \"Hip! Hip! Hooray!\" because of the surrounding <code><ng-template></code>.</p>\n<code-example path=\"structural-directives/src/app/app.component.html\" header=\"src/app/app.component.html (template-tag)\" region=\"template-tag\">\n<p>Hip!</p>\n<ng-template>\n <p>Hip!</p>\n</ng-template>\n<p>Hooray!</p>\n\n</code-example>\n<div class=\"lightbox\">\n <img src=\"generated/images/guide/structural-directives/template-rendering.png\" alt=\"template tag rendering\" width=\"520\" height=\"94\">\n</div>\n<h2 id=\"structural-directive-syntax-reference\">Structural directive syntax reference<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/structural-directives#structural-directive-syntax-reference\"><i class=\"material-icons\">link</i></a></h2>\n<p>When you write your own structural directives, use the following syntax:</p>\n<code-example>\n*:prefix=\"( :let | :expression ) (';' | ',')? ( :let | :as | :keyExp )*\"\n</code-example>\n<p>The following tables describe each portion of the structural directive grammar:</p>\n<table>\n <tbody><tr>\n <td><code>prefix</code></td>\n <td>HTML attribute key</td>\n </tr>\n <tr>\n <td><code>key</code></td>\n <td>HTML attribute key</td>\n </tr>\n <tr>\n <td><code>local</code></td>\n <td>local variable name used in the template</td>\n </tr>\n <tr>\n <td><code>export</code></td>\n <td>value exported by the directive under a given name</td>\n </tr>\n <tr>\n <td><code>expression</code></td>\n <td>standard Angular expression</td>\n </tr>\n</tbody></table>\n<table>\n <tbody><tr>\n <th></th>\n </tr>\n <tr>\n <td colspan=\"3\"><code>keyExp = :key \":\"? :expression (\"as\" :local)? \";\"? </code></td>\n </tr>\n <tr>\n <td colspan=\"3\"><code>let = \"let\" :local \"=\" :export \";\"?</code></td>\n </tr>\n <tr>\n <td colspan=\"3\"><code>as = :export \"as\" :local \";\"?</code></td>\n </tr>\n</tbody></table>\n<h3 id=\"how-angular-translates-shorthand\">How Angular translates shorthand<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/structural-directives#how-angular-translates-shorthand\"><i class=\"material-icons\">link</i></a></h3>\n<p>Angular translates structural directive shorthand into the normal binding syntax as follows:</p>\n<table>\n <tbody><tr>\n <th>Shorthand</th>\n <th>Translation</th>\n </tr>\n <tr>\n <td><code>prefix</code> and naked <code>expression</code></td>\n <td><code>[prefix]=\"expression\"</code></td>\n </tr>\n <tr>\n <td><code>keyExp</code></td>\n <td><code>[prefixKey] \"expression\"\n (let-prefixKey=\"export\")</code>\n <br>\n Notice that the <code>prefix</code>\n is added to the <code>key</code>\n </td>\n </tr>\n <tr>\n <td><code>let</code></td>\n <td><code>let-local=\"export\"</code></td>\n </tr>\n</tbody></table>\n<h3 id=\"shorthand-examples\">Shorthand examples<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/structural-directives#shorthand-examples\"><i class=\"material-icons\">link</i></a></h3>\n<p>The following table provides shorthand examples:</p>\n<table>\n <tbody><tr>\n <th>Shorthand</th>\n <th>How Angular interprets the syntax</th>\n </tr>\n <tr>\n <td><code>*<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a>=\"let item of [1,2,3]\"</code></td>\n <td><code><ng-template <a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a> let-item [<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngForOf</a>]=\"[1,2,3]\"></code></td>\n </tr>\n <tr>\n <td><code>*<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a>=\"let item of [1,2,3] as items; trackBy: myTrack; index as i\"</code></td>\n <td><code><ng-template <a href=\"api/common/NgForOf\" class=\"code-anchor\">ngFor</a> let-item [<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngForOf</a>]=\"[1,2,3]\" let-items=\"<a href=\"api/common/NgForOf\" class=\"code-anchor\">ngForOf</a>\" [ngForTrackBy]=\"myTrack\" let-i=\"index\"></code>\n </td>\n </tr>\n <tr>\n <td><code>*<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>=\"exp\"</code></td>\n <td><code><ng-template [<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>]=\"exp\"></code></td>\n </tr>\n <tr>\n <td><code>*<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>=\"exp as value\"</code></td>\n <td><code><ng-template [<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>]=\"exp\" let-value=\"<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>\"></code></td>\n </tr>\n</tbody></table>\n<a id=\"directive-type-checks\"></a>\n<!-- To do follow up PR: move this section to a more general location because it also applies to attribute directives. -->\n<h2 id=\"improving-template-type-checking-for-custom-directives\">Improving template type checking for custom directives<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/structural-directives#improving-template-type-checking-for-custom-directives\"><i class=\"material-icons\">link</i></a></h2>\n<p>You can improve template type checking for custom directives by adding template guard properties to your directive definition.\nThese properties help the Angular template type checker find mistakes in the template at compile time, which can avoid runtime errors.\nThese properties are as follows:</p>\n<ul>\n<li>A property <code>ngTemplateGuard_(someInputProperty)</code> lets you specify a more accurate type for an input expression within the template.</li>\n<li>The <code>ngTemplateContextGuard</code> static property declares the type of the template context.</li>\n</ul>\n<p>This section provides examples of both kinds of type-guard property.\nFor more information, see <a href=\"guide/template-typecheck\" title=\"Template type-checking guide\">Template type checking</a>.</p>\n<a id=\"narrowing-input-types\"></a>\n<h3 id=\"making-in-template-type-requirements-more-specific-with-template-guards\">Making in-template type requirements more specific with template guards<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/structural-directives#making-in-template-type-requirements-more-specific-with-template-guards\"><i class=\"material-icons\">link</i></a></h3>\n<p>A structural directive in a template controls whether that template is rendered at run time, based on its input expression.\nTo help the compiler catch template type errors, you should specify as closely as possible the required type of a directive's input expression when it occurs inside the template.</p>\n<p>A type guard function narrows the expected type of an input expression to a subset of types that might be passed to the directive within the template at run time.\nYou can provide such a function to help the type-checker infer the proper type for the expression at compile time.</p>\n<p>For example, the <code><a href=\"api/common/NgIf\" class=\"code-anchor\">NgIf</a></code> implementation uses type-narrowing to ensure that the\ntemplate is only instantiated if the input expression to <code>*<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a></code> is truthy.\nTo provide the specific type requirement, the <code><a href=\"api/common/NgIf\" class=\"code-anchor\">NgIf</a></code> directive defines a <a href=\"api/common/NgIf#static-properties\">static property <code>ngTemplateGuard_ngIf: 'binding'</code></a>.\nThe <code>binding</code> value is a special case for a common kind of type-narrowing where the input expression is evaluated in order to satisfy the type requirement.</p>\n<p>To provide a more specific type for an input expression to a directive within the template, add an <code>ngTemplateGuard_xx</code> property to the directive, where the suffix to the static property name, <code>xx</code>, is the <code>@<a href=\"api/core/Input\" class=\"code-anchor\">Input</a>()</code> field name.\nThe value of the property can be either a general type-narrowing function based on its return type, or the string <code>\"binding\"</code>, as in the case of <code><a href=\"api/common/NgIf\" class=\"code-anchor\">NgIf</a></code>.</p>\n<p>For example, consider the following structural directive that takes the result of a template expression as an input:</p>\n<code-example language=\"ts\" header=\"IfLoadedDirective\">\nexport type Loaded<t> = { type: 'loaded', data: T };\nexport type Loading = { type: 'loading' };\nexport type LoadingState<t> = Loaded<t> | Loading;\nexport class IfLoadedDirective<t> {\n @Input('ifLoaded') set state(state: LoadingState<t>) {}\n static ngTemplateGuard_state<t>(dir: IfLoadedDirective<t>, expr: LoadingState<t>): expr is Loaded<t> { return true; };\n}\n\nexport interface Person {\n name: string;\n}\n\n@Component({\n template: `<div *ifLoaded=\"state\">{{ state.data }}</div>`,\n})\nexport class AppComponent {\n state: LoadingState<person>;\n}\n</person></t></t></t></t></t></t></t></t></t></code-example>\n<p>In this example, the <code>LoadingState<T></code> type permits either of two states, <code>Loaded<T></code> or <code>Loading</code>. The expression used as the directive’s <code><a href=\"api/animations/state\" class=\"code-anchor\">state</a></code> input is of the umbrella type <code>LoadingState</code>, as it’s unknown what the loading state is at that point.</p>\n<p>The <code>IfLoadedDirective</code> definition declares the static field <code>ngTemplateGuard_state</code>, which expresses the narrowing behavior.\nWithin the <code>AppComponent</code> template, the <code>*ifLoaded</code> structural directive should render this template only when <code><a href=\"api/animations/state\" class=\"code-anchor\">state</a></code> is actually <code>Loaded<Person></code>.\nThe type guard allows the type checker to infer that the acceptable type of <code><a href=\"api/animations/state\" class=\"code-anchor\">state</a></code> within the template is a <code>Loaded<T></code>, and further infer that <code>T</code> must be an instance of <code>Person</code>.</p>\n<a id=\"narrowing-context-type\"></a>\n<h3 id=\"typing-the-directives-context\">Typing the directive's context<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/structural-directives#typing-the-directives-context\"><i class=\"material-icons\">link</i></a></h3>\n<p>If your structural directive provides a context to the instantiated template, you can properly type it inside the template by providing a static <code>ngTemplateContextGuard</code> function.\nThe following snippet shows an example of such a function.</p>\n<code-example language=\"ts\" header=\"myDirective.ts\">\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>({…})\nexport class ExampleDirective {\n // Make sure the template checker knows the type of the context with which the\n // template of this directive will be rendered\n <a href=\"api/upgrade/static\" class=\"code-anchor\">static</a> ngTemplateContextGuard(dir: ExampleDirective, ctx: unknown): ctx is ExampleContext { return true; };\n\n // …\n}\n</code-example>\n\n \n</div>\n\n<!-- links to this doc:\n - api/common\n - api/common/CommonModule\n - api/common/NgForOf\n - api/common/NgIf\n - api/common/NgSwitch\n - guide/ajs-quick-reference\n - guide/aot-compiler\n - guide/architecture-components\n - guide/bootstrapping\n - guide/built-in-directives\n - guide/example-apps-list\n - guide/glossary\n - guide/interpolation\n - guide/template-reference-variables\n - guide/template-statements\n - guide/template-typecheck\n - start\n-->\n<!-- links from this doc:\n - api/animations/state\n - api/common/NgClass\n - api/common/NgForOf\n - api/common/NgIf\n - api/common/NgIf#static-properties\n - api/common/NgSwitch\n - api/core/Directive\n - api/core/EmbeddedViewRef\n - api/core/Input\n - api/core/TemplateRef\n - api/core/ViewContainerRef\n - api/upgrade/static\n - guide/built-in-directives\n - guide/structural-directives#creating-a-structural-directive\n - guide/structural-directives#creating-template-fragments-with-ng-template\n - guide/structural-directives#how-angular-translates-shorthand\n - guide/structural-directives#improving-template-type-checking-for-custom-directives\n - guide/structural-directives#making-in-template-type-requirements-more-specific-with-template-guards\n - guide/structural-directives#shorthand-examples\n - guide/structural-directives#structural-directive-shorthand\n - guide/structural-directives#structural-directive-syntax-reference\n - guide/structural-directives#testing-the-directive\n - guide/structural-directives#typing-the-directives-context\n - guide/structural-directives#writing-structural-directives\n - guide/template-typecheck\n - https://github.com/angular/angular/edit/master/aio/content/guide/structural-directives.md?message=docs%3A%20describe%20your%20change...\n-->"
|
||
} |