feat(compiler): set `enableLegacyTemplate` to false by default (#18756)
BREAKING CHANGE: the compiler option `enableLegacyTemplate` is now disabled by default as the `<template>` element has been deprecated since v4. Use `<ng-template>` instead. The option `enableLegacyTemplate` and the `<template>` element will both be removed in Angular v6. PR Close #18756
|
@ -92,22 +92,22 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
The <code>hero.id</code> in the <template *ngIf> disappears:
|
||||
The <code>hero.id</code> in the <ng-template *ngIf> disappears:
|
||||
<p>
|
||||
<template *ngIf="showId">
|
||||
<ng-template *ngIf="showId">
|
||||
Id: ({{hero.id}})
|
||||
</template>
|
||||
</ng-template>
|
||||
Name: {{hero.name}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
The <code>hero.id</code> in the <template [ngIf]>
|
||||
The <code>hero.id</code> in the <ng-template [ngIf]>
|
||||
is unaffected by the <span>p-span</span> CSS:
|
||||
<p>
|
||||
<template [ngIf]="showId">
|
||||
<ng-template [ngIf]="showId">
|
||||
Id: ({{hero.id}})
|
||||
</template>
|
||||
</ng-template>
|
||||
Name: {{hero.name}}
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -18,9 +18,9 @@ describe('Structural Directives', function () {
|
|||
expect(allLis.get(0).getText()).toEqual('Mr. Nice');
|
||||
});
|
||||
|
||||
it('ngSwitch have three <happy-hero> instances', function () {
|
||||
it('ngSwitch have two <happy-hero> instances', function () {
|
||||
const happyHeroEls = element.all(by.tagName('happy-hero'));
|
||||
expect(happyHeroEls.count()).toEqual(3);
|
||||
expect(happyHeroEls.count()).toEqual(2);
|
||||
});
|
||||
|
||||
it('should toggle *ngIf="hero" with a button', function () {
|
||||
|
|
|
@ -55,11 +55,6 @@
|
|||
</ng-template>
|
||||
<!-- #enddocregion ngif-template -->
|
||||
|
||||
<p>template attribute</p>
|
||||
<!-- #docregion ngif-template-attr -->
|
||||
<div template="ngIf hero">{{hero.name}}</div>
|
||||
<!-- #enddocregion ngif-template-attr -->
|
||||
|
||||
<hr>
|
||||
|
||||
<h2 id="ng-container"><ng-container></h2>
|
||||
|
@ -131,14 +126,7 @@
|
|||
</div>
|
||||
|
||||
<!--#enddocregion inside-ngfor -->
|
||||
<p class="code"><div template="ngFor let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd"></p>
|
||||
<!--#docregion inside-ngfor -->
|
||||
<div template="ngFor let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd">
|
||||
({{i}}) {{hero.name}}
|
||||
</div>
|
||||
|
||||
<!--#enddocregion inside-ngfor -->
|
||||
<p class="code"><template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById"></p>
|
||||
<p class="code"><ng-template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById"/></p>
|
||||
<!--#docregion inside-ngfor -->
|
||||
<ng-template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById">
|
||||
<div [class.odd]="odd">({{i}}) {{hero.name}}</div>
|
||||
|
@ -169,16 +157,6 @@
|
|||
</div>
|
||||
<!-- #enddocregion built-in, ngswitch -->
|
||||
|
||||
<h4>NgSwitch with <i>template</i> attribute</h4>
|
||||
<!-- #docregion ngswitch-template-attr -->
|
||||
<div [ngSwitch]="hero?.emotion">
|
||||
<happy-hero template="ngSwitchCase 'happy'" [hero]="hero"></happy-hero>
|
||||
<sad-hero template="ngSwitchCase 'sad'" [hero]="hero"></sad-hero>
|
||||
<confused-hero template="ngSwitchCase 'confused'" [hero]="hero"></confused-hero>
|
||||
<unknown-hero template="ngSwitchDefault" [hero]="hero"></unknown-hero>
|
||||
</div>
|
||||
<!-- #enddocregion ngswitch-template-attr -->
|
||||
|
||||
<h4>NgSwitch with <ng-template></h4>
|
||||
<!-- #docregion ngswitch-template -->
|
||||
<div [ngSwitch]="hero?.emotion">
|
||||
|
@ -199,7 +177,7 @@
|
|||
|
||||
<hr>
|
||||
|
||||
<h2><template></h2>
|
||||
<h2><ng-template></h2>
|
||||
<!-- #docregion template-tag -->
|
||||
<p>Hip!</p>
|
||||
<ng-template>
|
||||
|
@ -238,13 +216,13 @@
|
|||
<p *myUnless="condition">Show this sentence unless the condition is true.</p>
|
||||
<!-- #enddocregion myUnless-1 -->
|
||||
|
||||
<p template="myUnless condition" class="code unless">
|
||||
(A) <p template="myUnless condition" class="code unless">
|
||||
<p *myUnless="condition" class="code unless">
|
||||
(A) <p *myUnless="condition" class="code unless">
|
||||
</p>
|
||||
|
||||
<ng-template [myUnless]="condition">
|
||||
<p class="code unless">
|
||||
(A) <template [myUnless]="condition">
|
||||
(A) <ng-template [myUnless]="condition">
|
||||
</p>
|
||||
</ng-template>
|
||||
|
||||
|
|
|
@ -19,8 +19,7 @@ import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
|
|||
* ### Syntax
|
||||
*
|
||||
* - `<div *myUnless="condition">...</div>`
|
||||
* - `<div template="myUnless condition">...</div>`
|
||||
* - `<template [myUnless]="condition"><div>...</div></template>`
|
||||
* - `<ng-template [myUnless]="condition"><div>...</div></ng-template>`
|
||||
*
|
||||
// #docregion no-docs
|
||||
*/
|
||||
|
|
|
@ -78,11 +78,11 @@
|
|||
|
||||
<p>Template input variable expression context (let hero)</p>
|
||||
<!-- template hides the following; plenty of examples later -->
|
||||
<template>
|
||||
<ng-template>
|
||||
<!-- #docregion context-var -->
|
||||
<div *ngFor="let hero of heroes">{{hero.name}}</div>
|
||||
<!-- #enddocregion context-var -->
|
||||
</template>
|
||||
</ng-template>
|
||||
|
||||
<p>Template reference variable expression context (#heroInput)</p>
|
||||
<div (keyup)="0" class="context">
|
||||
|
|
|
@ -208,17 +208,7 @@ Here is `*ngIf` displaying the hero's name if `hero` exists.
|
|||
|
||||
|
||||
The asterisk is "syntactic sugar" for something a bit more complicated.
|
||||
Internally, Angular desugars it in two stages.
|
||||
First, it translates the `*ngIf="..."` into a template _attribute_, `template="ngIf ..."`, like this.
|
||||
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-template-attr)" region="ngif-template-attr">
|
||||
|
||||
</code-example>
|
||||
|
||||
|
||||
|
||||
Then it translates the template _attribute_ into a `<ng-template>` _element_, wrapped around the host element, like this.
|
||||
Internally, Angular translates the `*ngIf` _attribute_ into a `<ng-template>` _element_, wrapped around the host element, like this.
|
||||
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngif-template)" region="ngif-template">
|
||||
|
@ -230,8 +220,7 @@ Then it translates the template _attribute_ into a `<ng-template>` _element_, wr
|
|||
* The `*ngIf` directive moved to the `<ng-template>` element where it became a property binding,`[ngIf]`.
|
||||
* The rest of the `<div>`, including its class attribute, moved inside the `<ng-template>` element.
|
||||
|
||||
None of these forms are actually rendered.
|
||||
Only the finished product ends up in the DOM.
|
||||
The first form is not actually rendered, only the finished product ends up in the DOM.
|
||||
|
||||
|
||||
<figure>
|
||||
|
@ -252,10 +241,9 @@ The [`NgFor`](guide/structural-directives#ngFor) and [`NgSwitch...`](guide/struc
|
|||
|
||||
## Inside _*ngFor_
|
||||
|
||||
Angular transforms the `*ngFor` in similar fashion from asterisk (*) syntax through
|
||||
template _attribute_ to `<ng-template>` _element_.
|
||||
Angular transforms the `*ngFor` in similar fashion from asterisk (*) syntax to `<ng-template>` _element_.
|
||||
|
||||
Here's a full-featured application of `NgFor`, written all three ways:
|
||||
Here's a full-featured application of `NgFor`, written both ways:
|
||||
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (inside-ngfor)" region="inside-ngfor">
|
||||
|
@ -415,16 +403,7 @@ The `<unknown-hero>` is the host element for the `*ngSwitchDefault`.
|
|||
|
||||
|
||||
As with other structural directives, the `NgSwitchCase` and `NgSwitchDefault`
|
||||
can be desugared into the template _attribute_ form.
|
||||
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngswitch-template-attr)" region="ngswitch-template-attr">
|
||||
|
||||
</code-example>
|
||||
|
||||
|
||||
|
||||
That, in turn, can be desugared into the `<ng-template>` element form.
|
||||
can be desugared into the `<ng-template>` element form.
|
||||
|
||||
|
||||
<code-example path="structural-directives/src/app/app.component.html" linenums="false" title="src/app/app.component.html (ngswitch-template)" region="ngswitch-template">
|
||||
|
@ -438,7 +417,7 @@ That, in turn, can be desugared into the `<ng-template>` element form.
|
|||
|
||||
## Prefer the asterisk (*) syntax.
|
||||
|
||||
The asterisk (*) syntax is more clear than the other desugared forms.
|
||||
The asterisk (*) syntax is more clear than the desugared form.
|
||||
Use [<ng-container>](guide/structural-directives#ng-container) when there's no single element
|
||||
to host the directive.
|
||||
|
||||
|
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 17 KiB |
BIN
aio/content/images/guide/structural-directives/template-rendering.png
Normal file → Executable file
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 5.1 KiB |
|
@ -79,7 +79,6 @@ export class NgForOfContext<T> {
|
|||
* ### Syntax
|
||||
*
|
||||
* - `<li *ngFor="let item of items; index as i; trackBy: trackByFn">...</li>`
|
||||
* - `<li template="ngFor let item of items; index as i; trackBy: trackByFn">...</li>`
|
||||
*
|
||||
* With `<ng-template>` element:
|
||||
*
|
||||
|
|
|
@ -75,7 +75,6 @@ import {Directive, EmbeddedViewRef, Input, TemplateRef, ViewContainerRef} from '
|
|||
*
|
||||
* Simple form:
|
||||
* - `<div *ngIf="condition">...</div>`
|
||||
* - `<div template="ngIf condition">...</div>`
|
||||
* - `<ng-template [ngIf]="condition"><div>...</div></ng-template>`
|
||||
*
|
||||
* Form with an else block:
|
||||
|
|
|
@ -101,7 +101,7 @@ export class CodeGenerator {
|
|||
translations: transContent,
|
||||
i18nFormat: cliOptions.i18nFormat || undefined,
|
||||
locale: cliOptions.locale || undefined, missingTranslation,
|
||||
enableLegacyTemplate: options.enableLegacyTemplate !== false,
|
||||
enableLegacyTemplate: options.enableLegacyTemplate === true,
|
||||
enableSummariesForJit: options.enableSummariesForJit !== false,
|
||||
preserveWhitespaces: options.preserveWhitespaces,
|
||||
});
|
||||
|
|
|
@ -90,7 +90,7 @@ export interface CompilerOptions extends ts.CompilerOptions {
|
|||
// Print extra information while running the compiler
|
||||
trace?: boolean;
|
||||
|
||||
// Whether to enable support for <template> and the template attribute (true by default)
|
||||
// Whether to enable support for <template> and the template attribute (false by default)
|
||||
enableLegacyTemplate?: boolean;
|
||||
|
||||
// Whether to enable lowering expressions lambdas and expressions in a reference value
|
||||
|
|
|
@ -65,7 +65,7 @@ export function createAotCompiler(compilerHost: AotCompilerHost, options: AotCom
|
|||
const config = new CompilerConfig({
|
||||
defaultEncapsulation: ViewEncapsulation.Emulated,
|
||||
useJit: false,
|
||||
enableLegacyTemplate: options.enableLegacyTemplate !== false,
|
||||
enableLegacyTemplate: options.enableLegacyTemplate === true,
|
||||
missingTranslation: options.missingTranslation,
|
||||
preserveWhitespaces: options.preserveWhitespaces,
|
||||
});
|
||||
|
|
|
@ -36,7 +36,7 @@ export class CompilerConfig {
|
|||
this.useJit = !!useJit;
|
||||
this.jitDevMode = !!jitDevMode;
|
||||
this.missingTranslation = missingTranslation || null;
|
||||
this.enableLegacyTemplate = enableLegacyTemplate !== false;
|
||||
this.enableLegacyTemplate = enableLegacyTemplate === true;
|
||||
this.preserveWhitespaces = preserveWhitespacesDefault(noUndefined(preserveWhitespaces));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,16 +121,19 @@ export function main() {
|
|||
schemas?: SchemaMetadata[], preserveWhitespaces?: boolean) => TemplateAst[];
|
||||
let console: ArrayConsole;
|
||||
|
||||
function commonBeforeEach() {
|
||||
function configureCompiler() {
|
||||
console = new ArrayConsole();
|
||||
beforeEach(() => {
|
||||
console = new ArrayConsole();
|
||||
TestBed.configureCompiler({
|
||||
providers: [
|
||||
{provide: Console, useValue: console},
|
||||
{provide: CompilerConfig, useValue: new CompilerConfig({enableLegacyTemplate: true})}
|
||||
],
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function commonBeforeEach() {
|
||||
beforeEach(inject([TemplateParser], (parser: TemplateParser) => {
|
||||
const someAnimation = new CompileAnimationEntryMetadata('someAnimation', []);
|
||||
const someTemplate = compileTemplateMetadata({animations: [someAnimation]});
|
||||
|
@ -286,6 +289,7 @@ export function main() {
|
|||
});
|
||||
});
|
||||
|
||||
configureCompiler();
|
||||
commonBeforeEach();
|
||||
|
||||
describe('security context', () => {
|
||||
|
@ -318,6 +322,7 @@ export function main() {
|
|||
TestBed.configureCompiler({providers: [TEST_COMPILER_PROVIDERS, MOCK_SCHEMA_REGISTRY]});
|
||||
});
|
||||
|
||||
configureCompiler();
|
||||
commonBeforeEach();
|
||||
|
||||
describe('parse', () => {
|
||||
|
@ -2129,13 +2134,13 @@ The pipe 'test' could not be found ("{{[ERROR ->]a | test}}"): TestComp@0:2`);
|
|||
|
||||
});
|
||||
|
||||
describe('Template Parser - opt-out `<template>` support', () => {
|
||||
describe('Template Parser - `<template>` support disabled by default', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureCompiler({
|
||||
providers: [{
|
||||
provide: CompilerConfig,
|
||||
useValue: new CompilerConfig({enableLegacyTemplate: false}),
|
||||
}],
|
||||
providers: [
|
||||
{provide: Console, useValue: console},
|
||||
{provide: CompilerConfig, useValue: new CompilerConfig()}
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {CompilerConfig} from '@angular/compiler';
|
||||
import {Compiler, ComponentFactory, ComponentRef, ErrorHandler, EventEmitter, Host, Inject, Injectable, InjectionToken, Injector, NO_ERRORS_SCHEMA, NgModule, NgModuleRef, OnDestroy, SkipSelf, ViewRef} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, ChangeDetectorRef, PipeTransform} from '@angular/core/src/change_detection/change_detection';
|
||||
import {getDebugContext} from '@angular/core/src/errors';
|
||||
|
@ -37,7 +38,14 @@ export function main() {
|
|||
function declareTests({useJit}: {useJit: boolean}) {
|
||||
describe('integration tests', function() {
|
||||
|
||||
beforeEach(() => { TestBed.configureCompiler({useJit}); });
|
||||
beforeEach(() => {
|
||||
TestBed.configureCompiler({
|
||||
useJit,
|
||||
providers: [
|
||||
{provide: CompilerConfig, useValue: new CompilerConfig({enableLegacyTemplate: true})}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
describe('react to record changes', function() {
|
||||
it('should consume text node changes', () => {
|
||||
|
|
|
@ -160,7 +160,7 @@ export class JitCompilerFactory implements CompilerFactory {
|
|||
useJit: true,
|
||||
defaultEncapsulation: ViewEncapsulation.Emulated,
|
||||
missingTranslation: MissingTranslationStrategy.Warning,
|
||||
enableLegacyTemplate: true,
|
||||
enableLegacyTemplate: false,
|
||||
};
|
||||
|
||||
this._defaultOptions = [compilerOptions, ...defaultOptions];
|
||||
|
|
|
@ -76,7 +76,7 @@ interface Options extends ts.CompilerOptions {
|
|||
// Print extra information while running the compiler
|
||||
trace?: boolean;
|
||||
|
||||
// Whether to enable support for <template> and the template attribute (true by default)
|
||||
// Whether to enable support for <template> and the template attribute (false by default)
|
||||
enableLegacyTemplate?: boolean;
|
||||
|
||||
// Whether to generate .ngsummary.ts files that allow to use AOTed artifacts
|
||||
|
|