From c0178de0e2d2162023ef81d2dbc358644ae37da8 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Sun, 11 Dec 2016 21:42:20 -0800 Subject: [PATCH] feat(NgTemplateOutlet): Make NgTemplateOutlet compatible with * syntax BREAKING CHANGE: - Deprecate `ngOutletContext`. Use `ngTemplateOutletContext` instead --- .../src/directives/ng_template_outlet.ts | 33 +++++++------ .../directives/ng_template_outlet_spec.ts | 15 +++--- .../ts/e2e_test/ngTemplateOutlet_spec.ts | 31 ++++++++++++ .../common/ngTemplateOutlet/ts/module.ts | 49 +++++++++++++++++++ tools/public_api_guard/common/index.d.ts | 5 +- 5 files changed, 111 insertions(+), 22 deletions(-) create mode 100644 modules/@angular/examples/common/ngTemplateOutlet/ts/e2e_test/ngTemplateOutlet_spec.ts create mode 100644 modules/@angular/examples/common/ngTemplateOutlet/ts/module.ts diff --git a/modules/@angular/common/src/directives/ng_template_outlet.ts b/modules/@angular/common/src/directives/ng_template_outlet.ts index 0804793698..9e3df0549f 100644 --- a/modules/@angular/common/src/directives/ng_template_outlet.ts +++ b/modules/@angular/common/src/directives/ng_template_outlet.ts @@ -15,42 +15,47 @@ import {Directive, EmbeddedViewRef, Input, OnChanges, SimpleChanges, TemplateRef * * @howToUse * ``` - * + * * ``` * * @description * - * You can attach a context object to the `EmbeddedViewRef` by setting `[ngOutletContext]`. - * `[ngOutletContext]` should be an object, the object's keys will be the local template variables - * available within the `TemplateRef`. + * You can attach a context object to the `EmbeddedViewRef` by setting `[ngTemplateOutletContext]`. + * `[ngTemplateOutletContext]` should be an object, the object's keys will be available for binding + * by the local template `let` declarations. * * Note: using the key `$implicit` in the context object will set it's value as default. * + * # Example + * + * {@example common/ngTemplateOutlet/ts/module.ts region='NgTemplateOutlet'} + * * @experimental */ @Directive({selector: '[ngTemplateOutlet]'}) export class NgTemplateOutlet implements OnChanges { private _viewRef: EmbeddedViewRef; - private _context: Object; - private _templateRef: TemplateRef; + + @Input() public ngTemplateOutletContext: Object; + + @Input() public ngTemplateOutlet: TemplateRef; constructor(private _viewContainerRef: ViewContainerRef) {} + /** + * @deprecated v4.0.0 - Renamed to ngTemplateOutletContext. + */ @Input() - set ngOutletContext(context: Object) { this._context = context; } - - @Input() - set ngTemplateOutlet(templateRef: TemplateRef) { this._templateRef = templateRef; } + set ngOutletContext(context: Object) { this.ngTemplateOutletContext = context; } ngOnChanges(changes: SimpleChanges) { if (this._viewRef) { this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._viewRef)); } - if (this._templateRef) { - this._viewRef = this._viewContainerRef.createEmbeddedView(this._templateRef, this._context); + if (this.ngTemplateOutlet) { + this._viewRef = this._viewContainerRef.createEmbeddedView( + this.ngTemplateOutlet, this.ngTemplateOutletContext); } } } diff --git a/modules/@angular/common/test/directives/ng_template_outlet_spec.ts b/modules/@angular/common/test/directives/ng_template_outlet_spec.ts index ac1a17b816..2197cf1d55 100644 --- a/modules/@angular/common/test/directives/ng_template_outlet_spec.ts +++ b/modules/@angular/common/test/directives/ng_template_outlet_spec.ts @@ -84,8 +84,8 @@ export function main() { })); it('should display template if context is null', async(() => { - const template = - ``; + const template = `` + + ``; fixture = createTestComponent(template); detectChangesAndExpectText(''); @@ -97,7 +97,8 @@ export function main() { it('should reflect initial context and changes', async(() => { const template = - ``; + `` + + ``; fixture = createTestComponent(template); fixture.detectChanges(); @@ -114,7 +115,8 @@ export function main() { it('should reflect user defined $implicit property in the context', async(() => { const template = - ``; + `` + + ``; fixture = createTestComponent(template); fixture.detectChanges(); @@ -128,7 +130,8 @@ export function main() { it('should reflect context re-binding', async(() => { const template = - ``; + `` + + ``; fixture = createTestComponent(template); fixture.detectChanges(); @@ -162,4 +165,4 @@ function createTestComponent(template: string): ComponentFixture return TestBed.overrideComponent(TestComponent, {set: {template: template}}) .configureTestingModule({schemas: [NO_ERRORS_SCHEMA]}) .createComponent(TestComponent); -} \ No newline at end of file +} diff --git a/modules/@angular/examples/common/ngTemplateOutlet/ts/e2e_test/ngTemplateOutlet_spec.ts b/modules/@angular/examples/common/ngTemplateOutlet/ts/e2e_test/ngTemplateOutlet_spec.ts new file mode 100644 index 0000000000..a57ea4fc9f --- /dev/null +++ b/modules/@angular/examples/common/ngTemplateOutlet/ts/e2e_test/ngTemplateOutlet_spec.ts @@ -0,0 +1,31 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {$, ExpectedConditions, browser, by, element} from 'protractor'; +import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; + +function waitForElement(selector: string) { + const EC = ExpectedConditions; + // Waits for the element with id 'abc' to be present on the dom. + browser.wait(EC.presenceOf($(selector)), 20000); +} + +describe('ngTemplateOutlet', () => { + const URL = 'common/ngTemplateOutlet/ts/'; + afterEach(verifyNoBrowserErrors); + + describe('ng-template-outlet-example', () => { + it('should render', () => { + browser.get(URL); + waitForElement('ng-template-outlet-example'); + expect(element.all(by.css('ng-template-outlet-example span')).getText()).toEqual([ + 'Hello', 'Hello World!', 'Ahoj Svet!' + ]); + }); + }); +}); diff --git a/modules/@angular/examples/common/ngTemplateOutlet/ts/module.ts b/modules/@angular/examples/common/ngTemplateOutlet/ts/module.ts new file mode 100644 index 0000000000..2f38060751 --- /dev/null +++ b/modules/@angular/examples/common/ngTemplateOutlet/ts/module.ts @@ -0,0 +1,49 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Component, NgModule, OnInit, TemplateRef, ViewChild} from '@angular/core'; +import {BrowserModule} from '@angular/platform-browser'; +import {Subject} from 'rxjs/Subject'; + + +// #docregion NgTemplateOutlet +@Component({ + selector: 'ng-template-outlet-example', + template: ` + +
+ +
+ +
+ + + + +` +}) +class NgTemplateOutletExample { + myContext = {$implicit: 'World', localSk: 'Svet'}; +} +// #enddocregion + + +@Component({ + selector: 'example-app', + template: `` +}) +class ExampleApp { +} + +@NgModule({ + imports: [BrowserModule], + declarations: [ExampleApp, NgTemplateOutletExample], + bootstrap: [ExampleApp] +}) +export class AppModule { +} diff --git a/tools/public_api_guard/common/index.d.ts b/tools/public_api_guard/common/index.d.ts index f3bd7a4200..595497fc86 100644 --- a/tools/public_api_guard/common/index.d.ts +++ b/tools/public_api_guard/common/index.d.ts @@ -188,8 +188,9 @@ export declare class NgSwitchDefault { /** @experimental */ export declare class NgTemplateOutlet implements OnChanges { - ngOutletContext: Object; - ngTemplateOutlet: TemplateRef; + /** @deprecated */ ngOutletContext: Object; + ngTemplateOutlet: TemplateRef; + ngTemplateOutletContext: Object; constructor(_viewContainerRef: ViewContainerRef); ngOnChanges(changes: SimpleChanges): void; }