feat(NgTemplateOutlet): add NgTemplateOutlet directive
This commits adds a new NgTemplateOutlet directive that can be used to create embeded views from a supplied TemplateRef. Closes #7615 Closes #8021
This commit is contained in:
parent
b602bd8c83
commit
f4e6994634
|
@ -6,6 +6,7 @@
|
||||||
export {NgClass} from './directives/ng_class';
|
export {NgClass} from './directives/ng_class';
|
||||||
export {NgFor} from './directives/ng_for';
|
export {NgFor} from './directives/ng_for';
|
||||||
export {NgIf} from './directives/ng_if';
|
export {NgIf} from './directives/ng_if';
|
||||||
|
export {NgTemplateOutlet} from './directives/ng_template_outlet';
|
||||||
export {NgStyle} from './directives/ng_style';
|
export {NgStyle} from './directives/ng_style';
|
||||||
export {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './directives/ng_switch';
|
export {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './directives/ng_switch';
|
||||||
export {NgPlural, NgPluralCase, NgLocalization} from './directives/ng_plural';
|
export {NgPlural, NgPluralCase, NgLocalization} from './directives/ng_plural';
|
||||||
|
|
|
@ -2,6 +2,7 @@ import {CONST_EXPR, Type} from 'angular2/src/facade/lang';
|
||||||
import {NgClass} from './ng_class';
|
import {NgClass} from './ng_class';
|
||||||
import {NgFor} from './ng_for';
|
import {NgFor} from './ng_for';
|
||||||
import {NgIf} from './ng_if';
|
import {NgIf} from './ng_if';
|
||||||
|
import {NgTemplateOutlet} from './ng_template_outlet';
|
||||||
import {NgStyle} from './ng_style';
|
import {NgStyle} from './ng_style';
|
||||||
import {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './ng_switch';
|
import {NgSwitch, NgSwitchWhen, NgSwitchDefault} from './ng_switch';
|
||||||
import {NgPlural, NgPluralCase} from './ng_plural';
|
import {NgPlural, NgPluralCase} from './ng_plural';
|
||||||
|
@ -50,6 +51,7 @@ export const CORE_DIRECTIVES: Type[] = CONST_EXPR([
|
||||||
NgClass,
|
NgClass,
|
||||||
NgFor,
|
NgFor,
|
||||||
NgIf,
|
NgIf,
|
||||||
|
NgTemplateOutlet,
|
||||||
NgStyle,
|
NgStyle,
|
||||||
NgSwitch,
|
NgSwitch,
|
||||||
NgSwitchWhen,
|
NgSwitchWhen,
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import {Directive, Input, ViewContainerRef, ViewRef, TemplateRef} from 'angular2/core';
|
||||||
|
import {isPresent} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and inserts an embedded view based on a prepared `TemplateRef`.
|
||||||
|
*
|
||||||
|
* ### Syntax
|
||||||
|
* - `<template [ngTemplateOutlet]="templateRefExpression"></template>`
|
||||||
|
*/
|
||||||
|
@Directive({selector: '[ngTemplateOutlet]'})
|
||||||
|
export class NgTemplateOutlet {
|
||||||
|
private _insertedViewRef: ViewRef;
|
||||||
|
|
||||||
|
constructor(private _viewContainerRef: ViewContainerRef) {}
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
set ngTemplateOutlet(templateRef: TemplateRef) {
|
||||||
|
if (isPresent(this._insertedViewRef)) {
|
||||||
|
this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._insertedViewRef));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPresent(templateRef)) {
|
||||||
|
this._insertedViewRef = this._viewContainerRef.createEmbeddedView(templateRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
import {
|
||||||
|
AsyncTestCompleter,
|
||||||
|
TestComponentBuilder,
|
||||||
|
beforeEach,
|
||||||
|
ddescribe,
|
||||||
|
describe,
|
||||||
|
el,
|
||||||
|
expect,
|
||||||
|
iit,
|
||||||
|
inject,
|
||||||
|
it,
|
||||||
|
xit,
|
||||||
|
} from 'angular2/testing_internal';
|
||||||
|
|
||||||
|
import {Component, Directive, TemplateRef, ContentChildren, QueryList} from 'angular2/core';
|
||||||
|
|
||||||
|
import {NgTemplateOutlet} from 'angular2/src/common/directives/ng_template_outlet';
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
describe('insert', () => {
|
||||||
|
it('should do nothing if templateRef is null',
|
||||||
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
|
var template = `<template [ngTemplateOutlet]="null"></template>`;
|
||||||
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
|
.createAsync(TestComponent)
|
||||||
|
.then((fixture) => {
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('');
|
||||||
|
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should insert content specified by TemplateRef',
|
||||||
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
|
var template =
|
||||||
|
`<tpl-refs #refs="tplRefs"><template>foo</template></tpl-refs><template [ngTemplateOutlet]="currentTplRef"></template>`;
|
||||||
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
|
.createAsync(TestComponent)
|
||||||
|
.then((fixture) => {
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('');
|
||||||
|
|
||||||
|
var refs = fixture.debugElement.children[0].getLocal('refs');
|
||||||
|
|
||||||
|
fixture.componentInstance.currentTplRef = refs.tplRefs.first;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('foo');
|
||||||
|
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should clear content if TemplateRef becomes null',
|
||||||
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
|
var template =
|
||||||
|
`<tpl-refs #refs="tplRefs"><template>foo</template></tpl-refs><template [ngTemplateOutlet]="currentTplRef"></template>`;
|
||||||
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
|
.createAsync(TestComponent)
|
||||||
|
.then((fixture) => {
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
var refs = fixture.debugElement.children[0].getLocal('refs');
|
||||||
|
|
||||||
|
fixture.componentInstance.currentTplRef = refs.tplRefs.first;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('foo');
|
||||||
|
|
||||||
|
fixture.componentInstance.currentTplRef = null;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('');
|
||||||
|
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should swap content if TemplateRef changes',
|
||||||
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
|
var template = `<tpl-refs #refs="tplRefs"><template>foo</template><template>bar</template></tpl-refs><template [ngTemplateOutlet]="currentTplRef"></template>`;
|
||||||
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
|
.createAsync(TestComponent)
|
||||||
|
.then((fixture) => {
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
var refs = fixture.debugElement.children[0].getLocal('refs');
|
||||||
|
|
||||||
|
fixture.componentInstance.currentTplRef = refs.tplRefs.first;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('foo');
|
||||||
|
|
||||||
|
fixture.componentInstance.currentTplRef = refs.tplRefs.last;
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(fixture.nativeElement).toHaveText('bar');
|
||||||
|
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Directive({selector: 'tpl-refs', exportAs: 'tplRefs'})
|
||||||
|
class CaptureTplRefs {
|
||||||
|
@ContentChildren(TemplateRef) tplRefs: QueryList<TemplateRef>;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({selector: 'test-cmp', directives: [NgTemplateOutlet, CaptureTplRefs], template: ''})
|
||||||
|
class TestComponent {
|
||||||
|
currentTplRef: TemplateRef;
|
||||||
|
}
|
|
@ -66,6 +66,7 @@ var NG_COMMON = [
|
||||||
'NgFormControl',
|
'NgFormControl',
|
||||||
'NgFormModel',
|
'NgFormModel',
|
||||||
'NgIf',
|
'NgIf',
|
||||||
|
'NgTemplateOutlet',
|
||||||
'NgModel',
|
'NgModel',
|
||||||
'NgSelectOption',
|
'NgSelectOption',
|
||||||
'NgStyle',
|
'NgStyle',
|
||||||
|
|
|
@ -736,6 +736,9 @@ const COMMON = [
|
||||||
'NgIf',
|
'NgIf',
|
||||||
'NgIf.constructor(_viewContainer:ViewContainerRef, _templateRef:TemplateRef)',
|
'NgIf.constructor(_viewContainer:ViewContainerRef, _templateRef:TemplateRef)',
|
||||||
'NgIf.ngIf=(newCondition:any)',
|
'NgIf.ngIf=(newCondition:any)',
|
||||||
|
'NgTemplateOutlet',
|
||||||
|
'NgTemplateOutlet.constructor(_viewContainerRef:ViewContainerRef)',
|
||||||
|
'NgTemplateOutlet.ngTemplateOutlet=(templateRef:TemplateRef)',
|
||||||
'NgLocalization',
|
'NgLocalization',
|
||||||
'NgLocalization.getPluralCategory(value:any):string',
|
'NgLocalization.getPluralCategory(value:any):string',
|
||||||
'NgModel',
|
'NgModel',
|
||||||
|
|
Loading…
Reference in New Issue