diff --git a/packages/core/test/acceptance/common_integration_spec.ts b/packages/core/test/acceptance/common_integration_spec.ts
new file mode 100644
index 0000000000..14615fb8f6
--- /dev/null
+++ b/packages/core/test/acceptance/common_integration_spec.ts
@@ -0,0 +1,541 @@
+/**
+ * @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, Directive} from '@angular/core';
+import {TestBed} from '@angular/core/testing';
+import {By} from '@angular/platform-browser';
+
+describe('@angular/common integration', () => {
+
+ describe('NgForOf', () => {
+ @Directive({selector: '[dir]'})
+ class MyDirective {
+ }
+
+ @Component({selector: 'app-child', template: '
comp text
'})
+ class ChildComponent {
+ }
+
+ @Component({selector: 'app-root', template: ''})
+ class AppComponent {
+ items: string[] = ['first', 'second'];
+ }
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({declarations: [AppComponent, ChildComponent, MyDirective]});
+ });
+
+ it('should update a loop', () => {
+ TestBed.overrideTemplate(
+ AppComponent, '');
+ const fixture = TestBed.createComponent(AppComponent);
+ fixture.detectChanges();
+
+ let listItems =
+ Array.from((fixture.nativeElement as HTMLUListElement).querySelectorAll('li'));
+ expect(listItems.map(li => li.textContent)).toEqual(['first', 'second']);
+
+ // change detection cycle, no model changes
+ fixture.detectChanges();
+ listItems = Array.from((fixture.nativeElement as HTMLUListElement).querySelectorAll('li'));
+ expect(listItems.map(li => li.textContent)).toEqual(['first', 'second']);
+
+ // remove the last item
+ const items = fixture.componentInstance.items;
+ items.length = 1;
+ fixture.detectChanges();
+
+ listItems = Array.from((fixture.nativeElement as HTMLUListElement).querySelectorAll('li'));
+ expect(listItems.map(li => li.textContent)).toEqual(['first']);
+
+ // change an item
+ items[0] = 'one';
+ fixture.detectChanges();
+ listItems = Array.from((fixture.nativeElement as HTMLUListElement).querySelectorAll('li'));
+ expect(listItems.map(li => li.textContent)).toEqual(['one']);
+
+ // add an item
+ items.push('two');
+ fixture.detectChanges();
+ listItems = Array.from((fixture.nativeElement as HTMLUListElement).querySelectorAll('li'));
+ expect(listItems.map(li => li.textContent)).toEqual(['one', 'two']);
+ });
+
+ it('should support ngForOf context variables', () => {
+ TestBed.overrideTemplate(
+ AppComponent,
+ '{{myIndex}} of {{myCount}}: {{item}} ');
+ const fixture = TestBed.createComponent(AppComponent);
+ fixture.detectChanges();
+
+ let listItems =
+ Array.from((fixture.nativeElement as HTMLUListElement).querySelectorAll('li'));
+ expect(listItems.map(li => li.textContent)).toEqual(['0 of 2: first', '1 of 2: second']);
+
+ // add an item in the middle
+ const items = fixture.componentInstance.items;
+ items.splice(1, 0, 'middle');
+ fixture.detectChanges();
+ listItems = Array.from((fixture.nativeElement as HTMLUListElement).querySelectorAll('li'));
+ expect(listItems.map(li => li.textContent)).toEqual([
+ '0 of 3: first', '1 of 3: middle', '2 of 3: second'
+ ]);
+ });
+
+ it('should instantiate directives inside directives properly in an ngFor', () => {
+ TestBed.overrideTemplate(AppComponent, ' ');
+ const fixture = TestBed.createComponent(AppComponent);
+ fixture.detectChanges();
+
+ const children = fixture.debugElement.queryAll(By.directive(ChildComponent));
+
+ // expect 2 children, each one with a directive
+ expect(children.length).toBe(2);
+ expect(children.map(child => child.nativeElement.innerHTML)).toEqual([
+ 'comp text
', 'comp text
'
+ ]);
+ let directive = children[0].query(By.directive(MyDirective));
+ expect(directive).not.toBeNull();
+ directive = children[1].query(By.directive(MyDirective));
+ expect(directive).not.toBeNull();
+
+ // add an item
+ const items = fixture.componentInstance.items;
+ items.push('third');
+ fixture.detectChanges();
+
+ const childrenAfterAdd = fixture.debugElement.queryAll(By.directive(ChildComponent));
+
+ expect(childrenAfterAdd.length).toBe(3);
+ expect(childrenAfterAdd.map(child => child.nativeElement.innerHTML)).toEqual([
+ 'comp text
', 'comp text
', 'comp text
'
+ ]);
+ directive = childrenAfterAdd[2].query(By.directive(MyDirective));
+ expect(directive).not.toBeNull();
+ });
+
+ it('should retain parent view listeners when the NgFor destroy views', () => {
+ @Component({
+ selector: 'app-toggle',
+ template: `Toggle List
+ `
+ })
+ class ToggleComponent {
+ private _data: number[] = [1, 2, 3];
+ items: number[] = [];
+
+ toggle() {
+ if (this.items.length) {
+ this.items = [];
+ } else {
+ this.items = this._data;
+ }
+ }
+ }
+
+ TestBed.configureTestingModule({declarations: [ToggleComponent]});
+ const fixture = TestBed.createComponent(ToggleComponent);
+ fixture.detectChanges();
+
+ // no elements in the list
+ let listItems =
+ Array.from((fixture.nativeElement as HTMLUListElement).querySelectorAll('li'));
+ expect(listItems.length).toBe(0);
+
+ // this will fill the list
+ fixture.componentInstance.toggle();
+ fixture.detectChanges();
+ listItems = Array.from((fixture.nativeElement as HTMLUListElement).querySelectorAll('li'));
+ expect(listItems.length).toBe(3);
+ expect(listItems.map(li => li.textContent)).toEqual(['1', '2', '3']);
+
+ // now toggle via the button
+ const button: HTMLButtonElement = fixture.nativeElement.querySelector('button');
+ button.click();
+ fixture.detectChanges();
+ listItems = Array.from((fixture.nativeElement as HTMLUListElement).querySelectorAll('li'));
+ expect(listItems.length).toBe(0);
+
+ // toggle again
+ button.click();
+ fixture.detectChanges();
+ listItems = Array.from((fixture.nativeElement as HTMLUListElement).querySelectorAll('li'));
+ expect(listItems.length).toBe(3);
+ });
+
+ it('should support multiple levels of embedded templates', () => {
+ @Component({
+ selector: 'app-multi',
+ template: `
+
+ {{cell}} - {{ row.value }} - {{ items.length }}
+
+ `
+ })
+ class MultiLevelComponent {
+ items: any[] = [{data: ['1', '2'], value: 'first'}, {data: ['3', '4'], value: 'second'}];
+ }
+
+ TestBed.configureTestingModule({declarations: [MultiLevelComponent]});
+ const fixture = TestBed.createComponent(MultiLevelComponent);
+ fixture.detectChanges();
+
+ // change detection cycle, no model changes
+ let listItems =
+ Array.from((fixture.nativeElement as HTMLUListElement).querySelectorAll('li'));
+ expect(listItems.length).toBe(2);
+ let spanItems = Array.from(listItems[0].querySelectorAll('span'));
+ expect(spanItems.map(span => span.textContent)).toEqual(['1 - first - 2', '2 - first - 2']);
+ spanItems = Array.from(listItems[1].querySelectorAll('span'));
+ expect(spanItems.map(span => span.textContent)).toEqual(['3 - second - 2', '4 - second - 2']);
+
+ // remove the last item
+ const items = fixture.componentInstance.items;
+ items.length = 1;
+ fixture.detectChanges();
+
+ listItems = Array.from((fixture.nativeElement as HTMLUListElement).querySelectorAll('li'));
+ expect(listItems.length).toBe(1);
+ spanItems = Array.from(listItems[0].querySelectorAll('span'));
+ expect(spanItems.map(span => span.textContent)).toEqual(['1 - first - 1', '2 - first - 1']);
+
+ // change an item
+ items[0].data[0] = 'one';
+ fixture.detectChanges();
+
+ listItems = Array.from((fixture.nativeElement as HTMLUListElement).querySelectorAll('li'));
+ expect(listItems.length).toBe(1);
+ spanItems = Array.from(listItems[0].querySelectorAll('span'));
+ expect(spanItems.map(span => span.textContent)).toEqual(['one - first - 1', '2 - first - 1']);
+
+ // add an item
+ items[1] = {data: ['three', '4'], value: 'third'};
+ fixture.detectChanges();
+
+ listItems = Array.from((fixture.nativeElement as HTMLUListElement).querySelectorAll('li'));
+ expect(listItems.length).toBe(2);
+ spanItems = Array.from(listItems[0].querySelectorAll('span'));
+ expect(spanItems.map(span => span.textContent)).toEqual(['one - first - 2', '2 - first - 2']);
+ spanItems = Array.from(listItems[1].querySelectorAll('span'));
+ expect(spanItems.map(span => span.textContent)).toEqual([
+ 'three - third - 2', '4 - third - 2'
+ ]);
+ });
+
+ it('should support multiple levels of embedded templates with listeners', () => {
+ @Component({
+ selector: 'app-multi',
+ template: `
+
+
+ {{ row.value }} - {{ name }}
+
+
`
+ })
+ class MultiLevelWithListenerComponent {
+ items: any[] = [{data: ['1'], value: 'first'}];
+ name = 'app';
+ events: string[] = [];
+
+ onClick(value: string, name: string) { this.events.push(value, name); }
+ }
+
+ TestBed.configureTestingModule({declarations: [MultiLevelWithListenerComponent]});
+ const fixture = TestBed.createComponent(MultiLevelWithListenerComponent);
+ fixture.detectChanges();
+
+ const elements = fixture.nativeElement.querySelectorAll('p');
+ expect(elements.length).toBe(1);
+ expect(elements[0].innerHTML).toBe(' first - app ');
+
+ const span: HTMLSpanElement = fixture.nativeElement.querySelector('span');
+ span.click();
+ expect(fixture.componentInstance.events).toEqual(['first', 'app']);
+
+ fixture.componentInstance.name = 'new name';
+ fixture.detectChanges();
+ expect(elements[0].innerHTML).toBe(' first - new name ');
+
+ span.click();
+ expect(fixture.componentInstance.events).toEqual(['first', 'app', 'first', 'new name']);
+ });
+
+ it('should support skipping contexts', () => {
+ @Component({
+ selector: 'app-multi',
+ template: `
+
+ {{ cell.value }} - {{ name }}
+
+
`
+ })
+ class SkippingContextComponent {
+ name = 'app';
+ items: any[] = [
+ [
+ // row
+ {value: 'one', data: ['1', '2']} // cell
+ ],
+ [{value: 'two', data: ['3', '4']}]
+ ];
+ }
+
+ TestBed.configureTestingModule({declarations: [SkippingContextComponent]});
+ const fixture = TestBed.createComponent(SkippingContextComponent);
+ fixture.detectChanges();
+
+ const elements = fixture.nativeElement.querySelectorAll('span');
+ expect(elements.length).toBe(4);
+ expect(elements[0].textContent).toBe('one - app');
+ expect(elements[1].textContent).toBe('one - app');
+ expect(elements[2].textContent).toBe('two - app');
+ expect(elements[3].textContent).toBe('two - app');
+
+ fixture.componentInstance.name = 'other';
+ fixture.detectChanges();
+ expect(elements[0].textContent).toBe('one - other');
+ expect(elements[1].textContent).toBe('one - other');
+ expect(elements[2].textContent).toBe('two - other');
+ expect(elements[3].textContent).toBe('two - other');
+ });
+
+ it('should support context for 9+ levels of embedded templates', () => {
+ @Component({
+ selector: 'app-multi',
+ template: `
+
+
+
+
+
+
+
+ {{ item8 }}.{{ item7.value }}.{{ item6.value }}.{{ item5.value }}.{{ item4.value }}.{{ item3.value }}.{{ item2.value }}.{{ item1.value }}.{{ item0.value }}.{{ value }}
+
+
+
+
+
+
+
+
`
+ })
+ class NineLevelsComponent {
+ value = 'App';
+ items: any[] = [
+ {
+ // item0
+ data: [{
+ // item1
+ data: [{
+ // item2
+ data: [{
+ // item3
+ data: [{
+ // item4
+ data: [{
+ // item5
+ data: [{
+ // item6
+ data: [{
+ // item7
+ data: [
+ '1', '2' // item8
+ ],
+ value: 'h'
+ }],
+ value: 'g'
+ }],
+ value: 'f'
+ }],
+ value: 'e'
+ }],
+ value: 'd'
+ }],
+ value: 'c'
+ }],
+ value: 'b'
+ }],
+ value: 'a'
+ },
+ {
+ // item0
+ data: [{
+ // item1
+ data: [{
+ // item2
+ data: [{
+ // item3
+ data: [{
+ // item4
+ data: [{
+ // item5
+ data: [{
+ // item6
+ data: [{
+ // item7
+ data: [
+ '3', '4' // item8
+ ],
+ value: 'H'
+ }],
+ value: 'G'
+ }],
+ value: 'F'
+ }],
+ value: 'E'
+ }],
+ value: 'D'
+ }],
+ value: 'C'
+ }],
+ value: 'B'
+ }],
+ value: 'A'
+ }
+ ];
+ }
+
+ TestBed.configureTestingModule({declarations: [NineLevelsComponent]});
+ const fixture = TestBed.createComponent(NineLevelsComponent);
+ fixture.detectChanges();
+
+ const divItems = (fixture.nativeElement as HTMLElement).querySelectorAll('div');
+ expect(divItems.length).toBe(2); // 2 outer loops
+ let spanItems =
+ divItems[0].querySelectorAll('span > span > span > span > span > span > span > span');
+ expect(spanItems.length).toBe(2); // 2 inner elements
+ expect(spanItems[0].textContent).toBe('1.h.g.f.e.d.c.b.a.App');
+ expect(spanItems[1].textContent).toBe('2.h.g.f.e.d.c.b.a.App');
+ spanItems =
+ divItems[1].querySelectorAll('span > span > span > span > span > span > span > span');
+ expect(spanItems.length).toBe(2); // 2 inner elements
+ expect(spanItems[0].textContent).toBe('3.H.G.F.E.D.C.B.A.App');
+ expect(spanItems[1].textContent).toBe('4.H.G.F.E.D.C.B.A.App');
+ });
+ });
+
+ describe('ngIf', () => {
+ it('should support sibling ngIfs', () => {
+ @Component({
+ selector: 'app-multi',
+ template: `
+ {{ valueOne }}
+ {{ valueTwo }}
+ `
+ })
+ class SimpleConditionComponent {
+ showing = true;
+ valueOne = 'one';
+ valueTwo = 'two';
+ }
+
+ TestBed.configureTestingModule({declarations: [SimpleConditionComponent]});
+ const fixture = TestBed.createComponent(SimpleConditionComponent);
+ fixture.detectChanges();
+
+ const elements = fixture.nativeElement.querySelectorAll('div');
+ expect(elements.length).toBe(2);
+ expect(elements[0].textContent).toBe('one');
+ expect(elements[1].textContent).toBe('two');
+
+ fixture.componentInstance.valueOne = '$$one$$';
+ fixture.componentInstance.valueTwo = '$$two$$';
+ fixture.detectChanges();
+ expect(elements[0].textContent).toBe('$$one$$');
+ expect(elements[1].textContent).toBe('$$two$$');
+ });
+
+ it('should handle nested ngIfs with no intermediate context vars', () => {
+ @Component({
+ selector: 'app-multi',
+ template: `
+ `
+ })
+ class NestedConditionsComponent {
+ showing = true;
+ outerShowing = true;
+ innerShowing = true;
+ name = 'App name';
+ }
+
+ TestBed.configureTestingModule({declarations: [NestedConditionsComponent]});
+ const fixture = TestBed.createComponent(NestedConditionsComponent);
+ fixture.detectChanges();
+
+ const elements = fixture.nativeElement.querySelectorAll('div');
+ expect(elements.length).toBe(3);
+ expect(elements[2].textContent).toBe('App name');
+
+ fixture.componentInstance.name = 'Other name';
+ fixture.detectChanges();
+ expect(elements[2].textContent).toBe('Other name');
+ });
+ });
+
+ describe('NgTemplateOutlet', () => {
+
+ it('should create and remove embedded views', () => {
+ @Component({
+ selector: 'app-multi',
+ template: `from tpl
+
+ `
+ })
+ class EmbeddedViewsComponent {
+ showing = false;
+ }
+
+ TestBed.configureTestingModule({declarations: [EmbeddedViewsComponent]});
+ const fixture = TestBed.createComponent(EmbeddedViewsComponent);
+ fixture.detectChanges();
+
+ expect(fixture.nativeElement.textContent).not.toBe('from tpl');
+
+ fixture.componentInstance.showing = true;
+ fixture.detectChanges();
+ expect(fixture.nativeElement.textContent).toBe('from tpl');
+
+ fixture.componentInstance.showing = false;
+ fixture.detectChanges();
+ expect(fixture.nativeElement.textContent).not.toBe('from tpl');
+ });
+
+ it('should create and remove embedded views', () => {
+ @Component({
+ selector: 'app-multi',
+ template: `from tpl
+
+ `
+ })
+ class NgContainerComponent {
+ showing = false;
+ }
+
+ TestBed.configureTestingModule({declarations: [NgContainerComponent]});
+ const fixture = TestBed.createComponent(NgContainerComponent);
+ fixture.detectChanges();
+
+ expect(fixture.nativeElement.textContent).not.toBe('from tpl');
+
+ fixture.componentInstance.showing = true;
+ fixture.detectChanges();
+ expect(fixture.nativeElement.textContent).toBe('from tpl');
+
+ fixture.componentInstance.showing = false;
+ fixture.detectChanges();
+ expect(fixture.nativeElement.textContent).not.toBe('from tpl');
+ });
+ });
+});
diff --git a/packages/core/test/render3/common_integration_spec.ts b/packages/core/test/render3/common_integration_spec.ts
deleted file mode 100644
index 029c154027..0000000000
--- a/packages/core/test/render3/common_integration_spec.ts
+++ /dev/null
@@ -1,1094 +0,0 @@
-/**
- * @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 {NgForOfContext} from '@angular/common';
-
-import {AttributeMarker, ɵɵdefineComponent, ɵɵelement, ɵɵgetCurrentView, ɵɵtemplateRefExtractor} from '../../src/render3/index';
-import {ɵɵbind, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementProperty, ɵɵelementStart, ɵɵinterpolation1, ɵɵinterpolation2, ɵɵinterpolation3, ɵɵinterpolationV, ɵɵlistener, ɵɵload, ɵɵnextContext, ɵɵreference, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all';
-import {RenderFlags} from '../../src/render3/interfaces/definition';
-import {ɵɵrestoreView} from '../../src/render3/state';
-
-import {NgForOf, NgIf, NgTemplateOutlet} from './common_with_def';
-import {ComponentFixture, createDirective, getDirectiveOnNode} from './render_util';
-
-describe('@angular/common integration', () => {
-
- describe('NgForOf', () => {
- it('should update a loop', () => {
- function liTemplate(rf: RenderFlags, ctx: NgForOfContext) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'li');
- { ɵɵtext(1); }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const item = ctx.$implicit;
- ɵɵtextBinding(1, ɵɵbind(item));
- }
- }
-
- class MyApp {
- items: string[] = ['first', 'second'];
-
- static ngComponentDef = ɵɵdefineComponent({
- type: MyApp,
- factory: () => new MyApp(),
- selectors: [['my-app']],
- consts: 2,
- vars: 1,
- //
- template: (rf: RenderFlags, ctx: MyApp) => {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'ul');
- {
- ɵɵtemplate(
- 1, liTemplate, 2, 1, 'li', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(1, 'ngForOf', ɵɵbind(ctx.items));
- }
- },
- directives: () => [NgForOf]
- });
- }
-
- const fixture = new ComponentFixture(MyApp);
- expect(fixture.html).toEqual('');
-
- // change detection cycle, no model changes
- fixture.update();
- expect(fixture.html).toEqual('');
-
- // remove the last item
- fixture.component.items.length = 1;
- fixture.update();
- expect(fixture.html).toEqual('');
-
- // change an item
- fixture.component.items[0] = 'one';
- fixture.update();
- expect(fixture.html).toEqual('');
-
- // add an item
- fixture.component.items.push('two');
- fixture.update();
- expect(fixture.html).toEqual('');
- });
-
- it('should support ngForOf context variables', () => {
- function liTemplate(rf: RenderFlags, ctx: NgForOfContext) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'li');
- { ɵɵtext(1); }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const item = ctx.$implicit;
- ɵɵtextBinding(1, ɵɵinterpolation3('', ctx.index, ' of ', ctx.count, ': ', item, ''));
- }
- }
-
- class MyApp {
- items: string[] = ['first', 'second'];
-
- static ngComponentDef = ɵɵdefineComponent({
- type: MyApp,
- factory: () => new MyApp(),
- selectors: [['my-app']],
- consts: 2,
- vars: 1,
- //
- // {{index}} of
- // {{count}}: {{item}}
- //
- template: (rf: RenderFlags, ctx: MyApp) => {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'ul');
- {
- ɵɵtemplate(
- 1, liTemplate, 2, 3, 'li', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(1, 'ngForOf', ɵɵbind(ctx.items));
- }
-
- },
- directives: () => [NgForOf]
- });
- }
-
- const fixture = new ComponentFixture(MyApp);
- expect(fixture.html).toEqual('0 of 2: first 1 of 2: second ');
-
- fixture.component.items.splice(1, 0, 'middle');
- fixture.update();
- expect(fixture.html)
- .toEqual('0 of 3: first 1 of 3: middle 2 of 3: second ');
- });
-
- it('should instantiate directives inside directives properly in an ngFor', () => {
- let dirs: any[] = [];
-
- const Dir = createDirective('dir');
-
- class Comp {
- static ngComponentDef = ɵɵdefineComponent({
- type: Comp,
- selectors: [['comp']],
- factory: () => new Comp(),
- consts: 2,
- vars: 0,
- template: (rf: RenderFlags, cmp: Comp) => {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'div', ['dir', '']);
- { ɵɵtext(1, 'comp text'); }
- ɵɵelementEnd();
- // testing only
- dirs.push(getDirectiveOnNode(0));
- }
- },
- directives: [Dir]
- });
- }
-
- function ngForTemplate(rf: RenderFlags, ctx: NgForOfContext) {
- if (rf & RenderFlags.Create) {
- ɵɵelement(0, 'comp');
- }
- }
-
- /** */
- class MyApp {
- rows: string[] = ['first', 'second'];
-
- static ngComponentDef = ɵɵdefineComponent({
- type: MyApp,
- factory: () => new MyApp(),
- selectors: [['my-app']],
- consts: 1,
- vars: 1,
- template: (rf: RenderFlags, ctx: MyApp) => {
- if (rf & RenderFlags.Create) {
- ɵɵtemplate(
- 0, ngForTemplate, 1, 0, 'comp', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(0, 'ngForOf', ɵɵbind(ctx.rows));
- }
- },
- directives: () => [NgForOf, Comp, Dir]
- });
- }
-
- const fixture = new ComponentFixture(MyApp);
- expect(fixture.html)
- .toEqual(
- 'comp text
comp text
');
- expect(dirs.length).toBe(2);
- expect(dirs[0] instanceof Dir).toBe(true);
- expect(dirs[1] instanceof Dir).toBe(true);
-
- fixture.component.rows.push('third');
- fixture.update();
- expect(dirs.length).toBe(3);
- expect(dirs[2] instanceof Dir).toBe(true);
- expect(fixture.html)
- .toEqual(
- 'comp text
comp text
comp text
');
- });
-
- it('should retain parent view listeners when the NgFor destroy views', () => {
-
- function liTemplate(rf: RenderFlags, ctx: NgForOfContext) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'li');
- { ɵɵtext(1); }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const item = ctx.$implicit;
- ɵɵtextBinding(1, ɵɵinterpolation1('', item, ''));
- }
- }
-
- class MyApp {
- private _data: number[] = [1, 2, 3];
- items: number[] = [];
-
- toggle() {
- if (this.items.length) {
- this.items = [];
- } else {
- this.items = this._data;
- }
- }
-
- static ngComponentDef = ɵɵdefineComponent({
- type: MyApp,
- factory: () => new MyApp(),
- selectors: [['my-app']],
- consts: 4,
- vars: 1,
- // Toggle List
- //
- template: (rf: RenderFlags, ctx: MyApp) => {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'button');
- {
- ɵɵlistener('click', function() { return ctx.toggle(); });
- ɵɵtext(1, 'Toggle List');
- }
- ɵɵelementEnd();
- ɵɵelementStart(2, 'ul');
- {
- ɵɵtemplate(
- 3, liTemplate, 2, 1, 'li', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(3, 'ngForOf', ɵɵbind(ctx.items));
- }
-
- },
- directives: () => [NgForOf]
- });
- }
-
- const fixture = new ComponentFixture(MyApp);
- const button = fixture.hostElement.querySelector('button') !;
-
- expect(fixture.html).toEqual('Toggle List ');
-
- // this will fill the list
- fixture.component.toggle();
- fixture.update();
- expect(fixture.html)
- .toEqual('Toggle List ');
-
- button.click();
- fixture.update();
-
- expect(fixture.html).toEqual('Toggle List ');
-
- button.click();
- fixture.update();
- expect(fixture.html)
- .toEqual('Toggle List ');
- });
-
- it('should support multiple levels of embedded templates', () => {
- /**
- *
- *
- * {{cell}} - {{ row.value }} - {{ items.length }}
- *
- *
- *
- */
- class MyApp {
- items: any[] = [{data: ['1', '2'], value: 'first'}, {data: ['3', '4'], value: 'second'}];
-
- static ngComponentDef = ɵɵdefineComponent({
- type: MyApp,
- factory: () => new MyApp(),
- selectors: [['my-app']],
- consts: 2,
- vars: 1,
- template: (rf: RenderFlags, ctx: MyApp) => {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'ul');
- {
- ɵɵtemplate(
- 1, liTemplate, 2, 1, 'li', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(1, 'ngForOf', ɵɵbind(ctx.items));
- }
-
- },
- directives: () => [NgForOf]
- });
- }
-
- function liTemplate(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'li');
- {
- ɵɵtemplate(
- 1, spanTemplate, 2, 3, 'span', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const row = ctx.$implicit as any;
- ɵɵelementProperty(1, 'ngForOf', ɵɵbind(row.data));
- }
- }
-
- function spanTemplate(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'span');
- { ɵɵtext(1); }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const cell = ctx.$implicit;
- const row = ɵɵnextContext().$implicit as any;
- const app = ɵɵnextContext() as any;
- ɵɵtextBinding(
- 1, ɵɵinterpolation3('', cell, ' - ', row.value, ' - ', app.items.length, ''));
- }
- }
-
- const fixture = new ComponentFixture(MyApp);
-
- // Change detection cycle, no model changes
- fixture.update();
- expect(fixture.html)
- .toEqual(
- '1 - first - 2 2 - first - 2 3 - second - 2 4 - second - 2 ');
-
- // Remove the last item
- fixture.component.items.length = 1;
- fixture.update();
- expect(fixture.html)
- .toEqual('1 - first - 1 2 - first - 1 ');
-
- // Change an item
- fixture.component.items[0].data[0] = 'one';
- fixture.update();
- expect(fixture.html)
- .toEqual('one - first - 1 2 - first - 1 ');
-
- // Add an item
- fixture.component.items[1] = {data: ['three', '4'], value: 'third'};
- fixture.update();
- expect(fixture.html)
- .toEqual(
- 'one - first - 2 2 - first - 2 three - third - 2 4 - third - 2 ');
- });
-
- it('should support multiple levels of embedded templates with listeners', () => {
- /**
- *
- *
- *
- * {{ row.value }} - {{ name }}
- *
- *
- */
- class MyApp {
- items: any[] = [{data: ['1'], value: 'first'}];
- name = 'app';
- events: string[] = [];
-
- onClick(value: string, name: string) { this.events.push(value, name); }
-
- static ngComponentDef = ɵɵdefineComponent({
- type: MyApp,
- factory: () => new MyApp(),
- selectors: [['my-app']],
- consts: 1,
- vars: 1,
- template: (rf: RenderFlags, ctx: MyApp) => {
- if (rf & RenderFlags.Create) {
- ɵɵtemplate(
- 0, divTemplate, 2, 1, 'div', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(0, 'ngForOf', ɵɵbind(ctx.items));
- }
-
- },
- directives: () => [NgForOf]
- });
- }
-
- function divTemplate(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'div');
- { ɵɵtemplate(1, pTemplate, 3, 2, 'p', [AttributeMarker.Template, 'ngFor', 'ngForOf']); }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const row = ctx.$implicit as any;
- ɵɵelementProperty(1, 'ngForOf', ɵɵbind(row.data));
- }
- }
-
- function pTemplate(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- const state = ɵɵgetCurrentView();
- ɵɵelementStart(0, 'p');
- {
- ɵɵelementStart(1, 'span');
- {
- ɵɵlistener('click', () => {
- ɵɵrestoreView(state);
- const row = ɵɵnextContext().$implicit as any;
- const app = ɵɵnextContext();
- app.onClick(row.value, app.name);
- });
- }
- ɵɵelementEnd();
- ɵɵtext(2);
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const row = ɵɵnextContext().$implicit as any;
- const app = ɵɵnextContext() as any;
- ɵɵtextBinding(2, ɵɵinterpolation2('', row.value, ' - ', app.name, ''));
- }
- }
-
- const fixture = new ComponentFixture(MyApp);
-
- fixture.update();
- expect(fixture.html).toEqual('');
-
- const span = fixture.hostElement.querySelector('span') as any;
- span.click();
- expect(fixture.component.events).toEqual(['first', 'app']);
-
- fixture.component.name = 'new name';
- fixture.update();
- expect(fixture.html).toEqual('');
-
- span.click();
- expect(fixture.component.events).toEqual(['first', 'app', 'first', 'new name']);
- });
-
- it('should support skipping contexts', () => {
- /**
- *
- *
- *
- * {{ cell.value }} - {{ name }}
- *
- *
- *
- */
- class MyApp {
- name = 'app';
- items: any[] = [
- [
- // row
- {value: 'one', data: ['1', '2']} // cell
- ],
- [{value: 'two', data: ['3', '4']}]
- ];
-
- static ngComponentDef = ɵɵdefineComponent({
- type: MyApp,
- factory: () => new MyApp(),
- selectors: [['my-app']],
- consts: 1,
- vars: 1,
- template: (rf: RenderFlags, ctx: MyApp) => {
- if (rf & RenderFlags.Create) {
- ɵɵtemplate(
- 0, divTemplate, 2, 1, 'div', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(0, 'ngForOf', ɵɵbind(ctx.items));
- }
-
- },
- directives: () => [NgForOf]
- });
- }
-
- function divTemplate(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'div');
- {
- ɵɵtemplate(
- 1, innerDivTemplate, 2, 1, 'div', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const row = ctx.$implicit as any;
- ɵɵelementProperty(1, 'ngForOf', ɵɵbind(row));
- }
- }
-
- function innerDivTemplate(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'div');
- {
- ɵɵtemplate(
- 1, spanTemplate, 2, 2, 'span', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const cell = ctx.$implicit as any;
- ɵɵelementProperty(1, 'ngForOf', ɵɵbind(cell.data));
- }
- }
-
- function spanTemplate(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'span');
- { ɵɵtext(1); }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const cell = ɵɵnextContext().$implicit as any;
- const app = ɵɵnextContext(2) as any;
- ɵɵtextBinding(1, ɵɵinterpolation2('', cell.value, ' - ', app.name, ''));
- }
- }
-
- const fixture = new ComponentFixture(MyApp);
-
- fixture.update();
- expect(fixture.html)
- .toEqual(
- ``);
-
- fixture.component.name = 'other';
- fixture.update();
- expect(fixture.html)
- .toEqual(
- ``);
- });
-
- it('should support context for 9+ levels of embedded templates', () => {
- /**
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- * {{ item8 }} - {{ item7.value }} - {{ item6.value }}...
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
- class MyApp {
- value = 'App';
- items: any[] = [
- {
- // item0
- data: [{
- // item1
- data: [{
- // item2
- data: [{
- // item3
- data: [{
- // item4
- data: [{
- // item5
- data: [{
- // item6
- data: [{
- // item7
- data: [
- '1', '2' // item8
- ],
- value: 'h'
- }],
- value: 'g'
- }],
- value: 'f'
- }],
- value: 'e'
- }],
- value: 'd'
- }],
- value: 'c'
- }],
- value: 'b'
- }],
- value: 'a'
- },
- {
- // item0
- data: [{
- // item1
- data: [{
- // item2
- data: [{
- // item3
- data: [{
- // item4
- data: [{
- // item5
- data: [{
- // item6
- data: [{
- // item7
- data: [
- '3', '4' // item8
- ],
- value: 'H'
- }],
- value: 'G'
- }],
- value: 'F'
- }],
- value: 'E'
- }],
- value: 'D'
- }],
- value: 'C'
- }],
- value: 'B'
- }],
- value: 'A'
- }
- ];
-
- static ngComponentDef = ɵɵdefineComponent({
- type: MyApp,
- factory: () => new MyApp(),
- selectors: [['my-app']],
- consts: 1,
- vars: 1,
- template: (rf: RenderFlags, ctx: MyApp) => {
- if (rf & RenderFlags.Create) {
- ɵɵtemplate(
- 0, itemTemplate0, 2, 1, 'span', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(0, 'ngForOf', ɵɵbind(ctx.items));
- }
-
- },
- directives: () => [NgForOf]
- });
- }
-
- function itemTemplate0(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'span');
- {
- ɵɵtemplate(
- 1, itemTemplate1, 2, 1, 'span', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const item0 = ctx.$implicit as any;
- ɵɵelementProperty(1, 'ngForOf', ɵɵbind(item0.data));
- }
- }
-
- function itemTemplate1(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'span');
- {
- ɵɵtemplate(
- 1, itemTemplate2, 2, 1, 'span', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const item1 = ctx.$implicit as any;
- ɵɵelementProperty(1, 'ngForOf', ɵɵbind(item1.data));
- }
- }
-
- function itemTemplate2(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'span');
- {
- ɵɵtemplate(
- 1, itemTemplate3, 2, 1, 'span', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const item2 = ctx.$implicit as any;
- ɵɵelementProperty(1, 'ngForOf', ɵɵbind(item2.data));
- }
- }
-
- function itemTemplate3(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'span');
- {
- ɵɵtemplate(
- 1, itemTemplate4, 2, 1, 'span', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const item3 = ctx.$implicit as any;
- ɵɵelementProperty(1, 'ngForOf', ɵɵbind(item3.data));
- }
- }
-
- function itemTemplate4(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'span');
- {
- ɵɵtemplate(
- 1, itemTemplate5, 2, 1, 'span', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const item4 = ctx.$implicit as any;
- ɵɵelementProperty(1, 'ngForOf', ɵɵbind(item4.data));
- }
- }
-
- function itemTemplate5(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'span');
- {
- ɵɵtemplate(
- 1, itemTemplate6, 2, 1, 'span', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const item5 = ctx.$implicit as any;
- ɵɵelementProperty(1, 'ngForOf', ɵɵbind(item5.data));
- }
- }
-
- function itemTemplate6(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'span');
- {
- ɵɵtemplate(
- 1, itemTemplate7, 2, 1, 'span', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const item6 = ctx.$implicit as any;
- ɵɵelementProperty(1, 'ngForOf', ɵɵbind(item6.data));
- }
- }
-
- function itemTemplate7(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'span');
- {
- ɵɵtemplate(
- 1, itemTemplate8, 2, 10, 'span', [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const item7 = ctx.$implicit as any;
- ɵɵelementProperty(1, 'ngForOf', ɵɵbind(item7.data));
- }
- }
-
- function itemTemplate8(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'span');
- { ɵɵtext(1); }
- ɵɵelementEnd();
- }
-
- if (rf & RenderFlags.Update) {
- const value = ctx.$implicit;
- const item7 = ɵɵnextContext().$implicit;
- const item6 = ɵɵnextContext().$implicit;
- const item5 = ɵɵnextContext().$implicit;
- const item4 = ɵɵnextContext().$implicit;
- const item3 = ɵɵnextContext().$implicit;
- const item2 = ɵɵnextContext().$implicit;
- const item1 = ɵɵnextContext().$implicit;
- const item0 = ɵɵnextContext().$implicit;
- const myApp = ɵɵnextContext();
- ɵɵtextBinding(1, ɵɵinterpolationV([
- '', value, '.', item7.value, '.', item6.value, '.', item5.value,
- '.', item4.value, '.', item3.value, '.', item2.value, '.', item1.value,
- '.', item0.value, '.', myApp.value, ''
- ]));
- }
- }
-
- const fixture = new ComponentFixture(MyApp);
-
- expect(fixture.html)
- .toEqual(
- '' +
- '1.h.g.f.e.d.c.b.a.App ' +
- '2.h.g.f.e.d.c.b.a.App ' +
- ' ' +
- '' +
- '3.H.G.F.E.D.C.B.A.App ' +
- '4.H.G.F.E.D.C.B.A.App ' +
- ' ');
- });
-
- });
-
- describe('ngIf', () => {
- it('should support sibling ngIfs', () => {
- class MyApp {
- showing = true;
- valueOne = 'one';
- valueTwo = 'two';
-
- static ngComponentDef = ɵɵdefineComponent({
- type: MyApp,
- factory: () => new MyApp(),
- selectors: [['my-app']],
- consts: 2,
- vars: 2,
- /**
- * {{ valueOne }}
- * {{ valueTwo }}
- */
- template: (rf: RenderFlags, ctx: MyApp) => {
- if (rf & RenderFlags.Create) {
- ɵɵtemplate(0, templateOne, 2, 1, 'div', [AttributeMarker.Template, 'ngIf']);
- ɵɵtemplate(1, templateTwo, 2, 1, 'div', [AttributeMarker.Template, 'ngIf']);
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(0, 'ngIf', ɵɵbind(ctx.showing));
- ɵɵelementProperty(1, 'ngIf', ɵɵbind(ctx.showing));
- }
-
- },
- directives: () => [NgIf]
- });
- }
-
- function templateOne(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'div');
- { ɵɵtext(1); }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const myApp = ɵɵnextContext();
- ɵɵtextBinding(1, ɵɵbind(myApp.valueOne));
- }
- }
-
- function templateTwo(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'div');
- { ɵɵtext(1); }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const myApp = ɵɵnextContext();
- ɵɵtextBinding(1, ɵɵbind(myApp.valueTwo));
- }
- }
-
- const fixture = new ComponentFixture(MyApp);
- expect(fixture.html).toEqual('one
two
');
-
- fixture.component.valueOne = '$$one$$';
- fixture.component.valueTwo = '$$two$$';
- fixture.update();
- expect(fixture.html).toEqual('$$one$$
$$two$$
');
- });
-
- it('should handle nested ngIfs with no intermediate context vars', () => {
- /**
- *
- *
- *
- * {{ name }}
- *
- *
- *
- */
- class AppComponent {
- showing = true;
- outerShowing = true;
- innerShowing = true;
- name = 'App name';
-
- static ngComponentDef = ɵɵdefineComponent({
- type: AppComponent,
- factory: () => new AppComponent(),
- selectors: [['my-app']],
- consts: 1,
- vars: 1,
- template: (rf: RenderFlags, ctx: AppComponent) => {
- if (rf & RenderFlags.Create) {
- ɵɵtemplate(0, divTemplate, 2, 1, 'div', [AttributeMarker.Template, 'ngIf']);
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(0, 'ngIf', ɵɵbind(ctx.showing));
- }
-
- },
- directives: () => [NgIf]
- });
- }
-
- function divTemplate(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'div');
- { ɵɵtemplate(1, outerDivTemplate, 2, 1, 'div', [AttributeMarker.Template, 'ngIf']); }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const app = ɵɵnextContext();
- ɵɵelementProperty(1, 'ngIf', ɵɵbind(app.outerShowing));
- }
- }
-
- function outerDivTemplate(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'div');
- { ɵɵtemplate(1, innerDivTemplate, 2, 1, 'div', [AttributeMarker.Template, 'ngIf']); }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const app = ɵɵnextContext(2);
- ɵɵelementProperty(1, 'ngIf', ɵɵbind(app.innerShowing));
- }
- }
-
- function innerDivTemplate(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'div');
- { ɵɵtext(1); }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const app = ɵɵnextContext(3);
- ɵɵtextBinding(1, ɵɵbind(app.name));
- }
- }
-
- const fixture = new ComponentFixture(AppComponent);
- expect(fixture.html).toEqual(``);
-
- fixture.component.name = 'Other name';
- fixture.update();
- expect(fixture.html).toEqual(``);
- });
-
- });
-
- describe('NgTemplateOutlet', () => {
-
- it('should create and remove embedded views', () => {
-
- class MyApp {
- showing = false;
- static ngComponentDef = ɵɵdefineComponent({
- type: MyApp,
- factory: () => new MyApp(),
- selectors: [['my-app']],
- consts: 3,
- vars: 1,
- /**
- * from tpl
- *
- */
- template: (rf: RenderFlags, myApp: MyApp) => {
- if (rf & RenderFlags.Create) {
- ɵɵtemplate(0, (rf1: RenderFlags) => {
- if (rf1 & RenderFlags.Create) {
- ɵɵtext(0, 'from tpl');
- }
- }, 1, 0, 'ng-template', undefined, ['tpl', ''], ɵɵtemplateRefExtractor);
- ɵɵtemplate(
- 2, null, 0, 0, 'ng-template', [AttributeMarker.Bindings, 'ngTemplateOutlet']);
- }
- if (rf & RenderFlags.Update) {
- const tplRef = ɵɵload(1);
- ɵɵelementProperty(2, 'ngTemplateOutlet', ɵɵbind(myApp.showing ? tplRef : null));
- }
- },
- directives: () => [NgTemplateOutlet]
- });
- }
-
- const fixture = new ComponentFixture(MyApp);
- expect(fixture.html).toEqual('');
-
- fixture.component.showing = true;
- fixture.update();
- expect(fixture.html).toEqual('from tpl');
-
- fixture.component.showing = false;
- fixture.update();
- expect(fixture.html).toEqual('');
- });
-
- it('should allow usage on ng-container', () => {
- class MyApp {
- showing = false;
- static ngComponentDef = ɵɵdefineComponent({
- type: MyApp,
- factory: () => new MyApp(),
- selectors: [['my-app']],
- consts: 3,
- vars: 1,
- /**
- * from tpl
- *
- */
- template: (rf: RenderFlags, myApp: MyApp) => {
- if (rf & RenderFlags.Create) {
- ɵɵtemplate(0, (rf1: RenderFlags) => {
- if (rf1 & RenderFlags.Create) {
- ɵɵtext(0, 'from tpl');
- }
- }, 1, 0, 'ng-template', undefined, ['tpl', ''], ɵɵtemplateRefExtractor);
- ɵɵelementContainerStart(2, [AttributeMarker.Bindings, 'ngTemplateOutlet']);
- ɵɵelementContainerEnd();
- }
- if (rf & RenderFlags.Update) {
- const tplRef = ɵɵreference(1);
- ɵɵelementProperty(2, 'ngTemplateOutlet', ɵɵbind(myApp.showing ? tplRef : null));
- }
- },
- directives: () => [NgTemplateOutlet]
- });
- }
-
- const fixture = new ComponentFixture(MyApp);
- expect(fixture.html).toEqual('');
-
- fixture.component.showing = true;
- fixture.update();
- expect(fixture.html).toEqual('from tpl');
-
- fixture.component.showing = false;
- fixture.update();
- expect(fixture.html).toEqual('');
-
- });
-
- });
-});