parent
4ed6cf7519
commit
164a091c71
@ -1,30 +1,53 @@
|
|||||||
import {Directive, Input, TemplateRef, ViewContainerRef, ViewRef} from '@angular/core';
|
import {Directive, Input, TemplateRef, ViewContainerRef, EmbeddedViewRef} from '@angular/core';
|
||||||
|
|
||||||
import {isPresent} from '../facade/lang';
|
import {isPresent} from '../facade/lang';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and inserts an embedded view based on a prepared `TemplateRef`.
|
* Creates and inserts an embedded view based on a prepared `TemplateRef`.
|
||||||
|
* 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`.
|
||||||
|
*
|
||||||
|
* Note: using the key `$implicit` in the context object will set it's value as default.
|
||||||
*
|
*
|
||||||
* ### Syntax
|
* ### Syntax
|
||||||
* - `<template [ngTemplateOutlet]="templateRefExpression"></template>`
|
* - `<template [ngTemplateOutlet]="templateRefExpression" [ngOutletContext]="objectExpression"></template>`
|
||||||
*
|
*
|
||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
@Directive({selector: '[ngTemplateOutlet]'})
|
@Directive({selector: '[ngTemplateOutlet]'})
|
||||||
export class NgTemplateOutlet {
|
export class NgTemplateOutlet {
|
||||||
private _insertedViewRef: ViewRef;
|
private _viewRef: EmbeddedViewRef<any>;
|
||||||
|
private _context: Object;
|
||||||
|
private _templateRef: TemplateRef<any>;
|
||||||
|
|
||||||
constructor(private _viewContainerRef: ViewContainerRef) {}
|
constructor(private _viewContainerRef: ViewContainerRef) {}
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set ngTemplateOutlet(templateRef: TemplateRef<Object>) {
|
set ngOutletContext(context: Object) {
|
||||||
if (isPresent(this._insertedViewRef)) {
|
if (this._context !== context) {
|
||||||
this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._insertedViewRef));
|
this._context = context;
|
||||||
|
if (isPresent(this._viewRef)) {
|
||||||
|
this.createView();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPresent(templateRef)) {
|
@Input()
|
||||||
this._insertedViewRef = this._viewContainerRef.createEmbeddedView(templateRef);
|
set ngTemplateOutlet(templateRef: TemplateRef<Object>) {
|
||||||
|
if (this._templateRef !== templateRef) {
|
||||||
|
this._templateRef = templateRef;
|
||||||
|
this.createView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private createView() {
|
||||||
|
if (isPresent(this._viewRef)) {
|
||||||
|
this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._viewRef));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPresent(this._templateRef)) {
|
||||||
|
this._viewRef = this._viewContainerRef.createEmbeddedView(this._templateRef, this._context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,91 @@ export function main() {
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should display template if context is null',
|
||||||
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
|
var template = `<tpl-refs #refs="tplRefs"><template>foo</template></tpl-refs><template [ngTemplateOutlet]="currentTplRef" [ngOutletContext]="null"></template>`;
|
||||||
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
|
.createAsync(TestComponent)
|
||||||
|
.then((fixture) => {
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('');
|
||||||
|
|
||||||
|
var refs = fixture.debugElement.children[0].references['refs'];
|
||||||
|
|
||||||
|
fixture.componentInstance.currentTplRef = refs.tplRefs.first;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('foo');
|
||||||
|
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should reflect initial context and changes',
|
||||||
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
|
var template =`<tpl-refs #refs="tplRefs"><template let-foo="foo"><span>{{foo}}</span></template></tpl-refs><template [ngTemplateOutlet]="currentTplRef" [ngOutletContext]="context"></template>`;
|
||||||
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
|
.createAsync(TestComponent)
|
||||||
|
.then((fixture) => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
var refs = fixture.debugElement.children[0].references['refs'];
|
||||||
|
fixture.componentInstance.currentTplRef = refs.tplRefs.first;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.debugElement.nativeElement).toHaveText('bar');
|
||||||
|
|
||||||
|
fixture.componentInstance.context.foo = 'alter-bar';
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.debugElement.nativeElement).toHaveText('alter-bar');
|
||||||
|
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should reflect user defined $implicit property in the context',
|
||||||
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
|
var template =`<tpl-refs #refs="tplRefs"><template let-ctx><span>{{ctx.foo}}</span></template></tpl-refs><template [ngTemplateOutlet]="currentTplRef" [ngOutletContext]="context"></template>`;
|
||||||
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
|
.createAsync(TestComponent)
|
||||||
|
.then((fixture) => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
var refs = fixture.debugElement.children[0].references['refs'];
|
||||||
|
fixture.componentInstance.currentTplRef = refs.tplRefs.first;
|
||||||
|
|
||||||
|
fixture.componentInstance.context = { $implicit: fixture.componentInstance.context };
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.debugElement.nativeElement).toHaveText('bar');
|
||||||
|
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should reflect context re-binding',
|
||||||
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
|
var template =`<tpl-refs #refs="tplRefs"><template let-shawshank="shawshank"><span>{{shawshank}}</span></template></tpl-refs><template [ngTemplateOutlet]="currentTplRef" [ngOutletContext]="context"></template>`;
|
||||||
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
|
.createAsync(TestComponent)
|
||||||
|
.then((fixture) => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
var refs = fixture.debugElement.children[0].references['refs'];
|
||||||
|
fixture.componentInstance.currentTplRef = refs.tplRefs.first;
|
||||||
|
fixture.componentInstance.context = { shawshank: 'brooks' };
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.debugElement.nativeElement).toHaveText('brooks');
|
||||||
|
|
||||||
|
fixture.componentInstance.context = { shawshank: 'was here' };
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.debugElement.nativeElement).toHaveText('was here');
|
||||||
|
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,4 +192,5 @@ class CaptureTplRefs {
|
|||||||
@Component({selector: 'test-cmp', directives: [NgTemplateOutlet, CaptureTplRefs], template: ''})
|
@Component({selector: 'test-cmp', directives: [NgTemplateOutlet, CaptureTplRefs], template: ''})
|
||||||
class TestComponent {
|
class TestComponent {
|
||||||
currentTplRef: TemplateRef<any>;
|
currentTplRef: TemplateRef<any>;
|
||||||
|
context: any = { foo: 'bar' };
|
||||||
}
|
}
|
||||||
|
@ -988,6 +988,7 @@ const COMMON = [
|
|||||||
'NgSwitchDefault.constructor(viewContainer:ViewContainerRef, templateRef:TemplateRef<Object>, sswitch:NgSwitch)',
|
'NgSwitchDefault.constructor(viewContainer:ViewContainerRef, templateRef:TemplateRef<Object>, sswitch:NgSwitch)',
|
||||||
'NgTemplateOutlet',
|
'NgTemplateOutlet',
|
||||||
'NgTemplateOutlet.constructor(_viewContainerRef:ViewContainerRef)',
|
'NgTemplateOutlet.constructor(_viewContainerRef:ViewContainerRef)',
|
||||||
|
'NgTemplateOutlet.ngOutletContext=(context:Object)',
|
||||||
'NgTemplateOutlet.ngTemplateOutlet=(templateRef:TemplateRef<Object>)',
|
'NgTemplateOutlet.ngTemplateOutlet=(templateRef:TemplateRef<Object>)',
|
||||||
'PathLocationStrategy',
|
'PathLocationStrategy',
|
||||||
'PathLocationStrategy.back():void',
|
'PathLocationStrategy.back():void',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user