diff --git a/packages/core/test/acceptance/content_spec.ts b/packages/core/test/acceptance/content_spec.ts
index dff0702576..c84aa1d5fc 100644
--- a/packages/core/test/acceptance/content_spec.ts
+++ b/packages/core/test/acceptance/content_spec.ts
@@ -6,11 +6,393 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {ChangeDetectorRef, Component, Directive} from '@angular/core';
+import {CommonModule} from '@angular/common';
+import {ChangeDetectorRef, Component, Directive, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core';
+import {Input} from '@angular/core/src/metadata';
import {TestBed} from '@angular/core/testing';
+import {By} from '@angular/platform-browser';
import {expect} from '@angular/platform-browser/testing/src/matchers';
describe('projection', () => {
+
+ function getElementHtml(element: HTMLElement) {
+ return element.innerHTML.replace(//g, '')
+ .replace(/\sng-reflect-\S*="[^"]*"/g, '');
+ }
+
+ it('should project content', () => {
+ @Component({selector: 'child', template: `
`})
+ class Child {
+ }
+
+ @Component({selector: 'parent', template: 'content'})
+ class Parent {
+ }
+
+ TestBed.configureTestingModule({declarations: [Parent, Child]});
+ const fixture = TestBed.createComponent(Parent);
+ fixture.detectChanges();
+
+ expect(fixture.nativeElement.innerHTML).toBe(`content
`);
+ });
+
+ it('should project content when is at a template root', () => {
+ @Component({
+ selector: 'child',
+ template: '',
+ })
+ class Child {
+ }
+
+ @Component({
+ selector: 'parent',
+ template: 'content',
+ })
+ class Parent {
+ }
+
+ TestBed.configureTestingModule({declarations: [Parent, Child]});
+ const fixture = TestBed.createComponent(Parent);
+ fixture.detectChanges();
+
+ expect(fixture.nativeElement.innerHTML).toBe(`content`);
+ });
+
+ it('should project content with siblings', () => {
+ @Component({selector: 'child', template: ''})
+ class Child {
+ }
+
+ @Component({selector: 'parent', template: `beforecontent
after`})
+ class Parent {
+ }
+
+
+ TestBed.configureTestingModule({declarations: [Parent, Child]});
+ const fixture = TestBed.createComponent(Parent);
+ fixture.detectChanges();
+
+ expect(fixture.nativeElement.innerHTML).toBe(`beforecontent
after`);
+ });
+
+ it('should be able to re-project content', () => {
+ @Component({selector: 'grand-child', template: `
`})
+ class GrandChild {
+ }
+
+ @Component(
+ {selector: 'child', template: ``})
+ class Child {
+ }
+
+ @Component({
+ selector: 'parent',
+ template: `HelloWorld!`,
+ })
+ class Parent {
+ }
+
+ TestBed.configureTestingModule({declarations: [Parent, Child, GrandChild]});
+ const fixture = TestBed.createComponent(Parent);
+ fixture.detectChanges();
+
+ expect(fixture.nativeElement.innerHTML)
+ .toBe('HelloWorld!
');
+ });
+
+ it('should project components', () => {
+ @Component({
+ selector: 'child',
+ template: `
`,
+ })
+ class Child {
+ }
+
+ @Component({
+ selector: 'projected-comp',
+ template: 'content',
+ })
+ class ProjectedComp {
+ }
+
+ @Component({selector: 'parent', template: ``})
+ class Parent {
+ }
+
+ TestBed.configureTestingModule({declarations: [Parent, Child, ProjectedComp]});
+ const fixture = TestBed.createComponent(Parent);
+ fixture.detectChanges();
+
+ expect(fixture.nativeElement.innerHTML)
+ .toBe('');
+ });
+
+ it('should project components that have their own projection', () => {
+ @Component({selector: 'child', template: `
`})
+ class Child {
+ }
+
+ @Component({selector: 'projected-comp', template: `
`})
+ class ProjectedComp {
+ }
+
+ @Component({
+ selector: 'parent',
+ template: `
+
+ Some content
Other content
+ `,
+ })
+ class Parent {
+ }
+
+ TestBed.configureTestingModule({declarations: [Parent, Child, ProjectedComp]});
+ const fixture = TestBed.createComponent(Parent);
+ fixture.detectChanges();
+
+ expect(fixture.nativeElement.innerHTML)
+ .toBe(
+ `Some content
Other content `);
+ });
+
+ it('should project into dynamic views (with createEmbeddedView)', () => {
+ @Component({
+ selector: 'child',
+ template: `Before--After`
+ })
+ class Child {
+ showing = false;
+ }
+
+ @Component({selector: 'parent', template: `A
Some text`})
+ class Parent {
+ }
+
+ TestBed.configureTestingModule({declarations: [Parent, Child], imports: [CommonModule]});
+
+ const fixture = TestBed.createComponent(Parent);
+ const childDebugEl = fixture.debugElement.query(By.directive(Child));
+ const childInstance = childDebugEl.injector.get(Child);
+ const childElement = childDebugEl.nativeElement as HTMLElement;
+
+ childInstance.showing = true;
+ fixture.detectChanges();
+
+ expect(getElementHtml(childElement)).toBe(`Before-A
Some text-After`);
+
+ childInstance.showing = false;
+ fixture.detectChanges();
+
+ expect(getElementHtml(childElement)).toBe(`Before--After`);
+
+ childInstance.showing = true;
+ fixture.detectChanges();
+ expect(getElementHtml(childElement)).toBe(`Before-A
Some text-After`);
+ });
+
+ it('should project into dynamic views with specific selectors', () => {
+ @Component({
+ selector: 'child',
+ template: `
+
+ Before-
+
+
+
+ -After`
+ })
+ class Child {
+ showing = false;
+ }
+
+ @Component({
+ selector: 'parent',
+ template: `
+
+ A
+ B
+
+ `
+ })
+ class Parent {
+ }
+
+ TestBed.configureTestingModule({declarations: [Parent, Child], imports: [CommonModule]});
+
+ const fixture = TestBed.createComponent(Parent);
+ const childDebugEl = fixture.debugElement.query(By.directive(Child));
+ const childInstance = childDebugEl.injector.get(Child);
+
+ childInstance.showing = true;
+ fixture.detectChanges();
+
+ expect(getElementHtml(fixture.nativeElement))
+ .toBe('B Before- A
-After');
+
+ childInstance.showing = false;
+ fixture.detectChanges();
+ expect(getElementHtml(fixture.nativeElement))
+ .toBe('B Before- -After');
+
+ childInstance.showing = true;
+ fixture.detectChanges();
+ expect(getElementHtml(fixture.nativeElement))
+ .toBe('B Before- A
-After');
+ });
+
+ it('should project if is in a template that has different declaration/insertion points',
+ () => {
+ @Component(
+ {selector: 'comp', template: ``})
+ class Comp {
+ @ViewChild(TemplateRef) template !: TemplateRef;
+ }
+
+ @Directive({selector: '[trigger]'})
+ class Trigger {
+ @Input() trigger !: Comp;
+
+ constructor(public vcr: ViewContainerRef) {}
+
+ open() { this.vcr.createEmbeddedView(this.trigger.template); }
+ }
+
+ @Component({
+ selector: 'parent',
+ template: `
+
+ Some content
+ `
+ })
+ class Parent {
+ }
+
+ TestBed.configureTestingModule({declarations: [Parent, Trigger, Comp]});
+
+ const fixture = TestBed.createComponent(Parent);
+ const trigger = fixture.debugElement.query(By.directive(Trigger)).injector.get(Trigger);
+ fixture.detectChanges();
+
+ expect(getElementHtml(fixture.nativeElement)).toBe(``);
+
+ trigger.open();
+ expect(getElementHtml(fixture.nativeElement))
+ .toBe(`Some content`);
+ });
+
+ // https://stackblitz.com/edit/angular-ceqmnw?file=src%2Fapp%2Fapp.component.ts
+ it('should project nodes into the last ng-content unrolled by ngFor', () => {
+ @Component({
+ selector: 'child',
+ template:
+ `({{i}}):
`
+ })
+ class Child {
+ }
+
+ @Component({selector: 'parent', template: `content`})
+ class Parent {
+ }
+
+ TestBed.configureTestingModule({declarations: [Parent, Child], imports: [CommonModule]});
+ const fixture = TestBed.createComponent(Parent);
+ fixture.detectChanges();
+
+ expect(getElementHtml(fixture.nativeElement))
+ .toBe('(0):
(1):content
');
+ });
+
+ it('should handle projected containers inside other containers', () => {
+ @Component({selector: 'nested-comp', template: `Child content
`})
+ class NestedComp {
+ }
+
+ @Component({
+ selector: 'root-comp',
+ template: ``,
+ })
+ class RootComp {
+ }
+
+ @Component({
+ selector: 'my-app',
+ template: `
+
+
+
+
+
+ `
+ })
+ class MyApp {
+ items = [1, 2];
+ }
+
+ TestBed.configureTestingModule(
+ {declarations: [MyApp, RootComp, NestedComp], imports: [CommonModule]});
+ const fixture = TestBed.createComponent(MyApp);
+ fixture.detectChanges();
+
+ // expecting # of divs to be (items.length - 1), since last element is filtered out by *ngIf,
+ // this applies to all other assertions below
+ expect(fixture.nativeElement.querySelectorAll('div').length).toBe(1);
+
+ fixture.componentInstance.items = [3, 4, 5];
+ fixture.detectChanges();
+ expect(fixture.nativeElement.querySelectorAll('div').length).toBe(2);
+
+ fixture.componentInstance.items = [6, 7, 8, 9];
+ fixture.detectChanges();
+ expect(fixture.nativeElement.querySelectorAll('div').length).toBe(3);
+ });
+
+ describe('with selectors', () => {
+ // https://stackblitz.com/edit/angular-psokum?file=src%2Fapp%2Fapp.module.ts
+ it('should project nodes where attribute selector matches a binding', () => {
+ @Component({
+ selector: 'child',
+ template: ``,
+ })
+ class Child {
+ }
+
+ @Component({
+ selector: 'parent',
+ template: `Has title`
+ })
+ class Parent {
+ }
+
+ TestBed.configureTestingModule({declarations: [Child, Parent]});
+ const fixture = TestBed.createComponent(Parent);
+ fixture.detectChanges();
+
+ expect(getElementHtml(fixture.nativeElement))
+ .toEqual('Has title');
+
+ });
+
+ it('should match selectors against projected containers', () => {
+ @Component(
+ {selector: 'child', template: ``})
+ class Child {
+ }
+
+ @Component({template: `content
`})
+ class Parent {
+ value = false;
+ }
+ TestBed.configureTestingModule({declarations: [Child, Parent]});
+ const fixture = TestBed.createComponent(Parent);
+
+ fixture.componentInstance.value = true;
+ fixture.detectChanges();
+
+ expect(getElementHtml(fixture.nativeElement))
+ .toEqual('content
');
+ });
+ });
+
it('should handle projected containers inside other containers', () => {
@Component({
selector: 'child-comp', //
diff --git a/packages/core/test/render3/content_spec.ts b/packages/core/test/render3/content_spec.ts
index f2109372eb..49aa362f8f 100644
--- a/packages/core/test/render3/content_spec.ts
+++ b/packages/core/test/render3/content_spec.ts
@@ -6,231 +6,14 @@
* found in the LICENSE file at https://angular.io/license
*/
-import {QueryList, TemplateRef, ViewContainerRef} from '@angular/core';
import {SelectorFlags} from '@angular/core/src/render3/interfaces/projection';
-import {AttributeMarker, detectChanges, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdirectiveInject, ɵɵloadViewQuery, ɵɵqueryRefresh, ɵɵreference, ɵɵtemplateRefExtractor, ɵɵviewQuery} from '../../src/render3/index';
-import {ɵɵbind, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementProperty, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵinterpolation1, ɵɵprojection, ɵɵprojectionDef, ɵɵtemplate, ɵɵtext, ɵɵtextBinding} from '../../src/render3/instructions/all';
+import {AttributeMarker, detectChanges} from '../../src/render3/index';
+import {ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵprojection, ɵɵprojectionDef, ɵɵtext} from '../../src/render3/instructions/all';
import {RenderFlags} from '../../src/render3/interfaces/definition';
-
-import {NgForOf, NgIf} from './common_with_def';
import {ComponentFixture, createComponent, getDirectiveOnNode, renderComponent, toHtml} from './render_util';
describe('content projection', () => {
- it('should project content', () => {
-
- /**
- *
- */
- const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵprojectionDef();
- ɵɵelementStart(0, 'div');
- { ɵɵprojection(1); }
- ɵɵelementEnd();
- }
- }, 2);
-
- /**
- * content
- */
- const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'child');
- { ɵɵtext(1, 'content'); }
- ɵɵelementEnd();
- }
- }, 2, 0, [Child]);
-
- const parent = renderComponent(Parent);
- expect(toHtml(parent)).toEqual('content
');
- });
-
- it('should project content when is at a template root', () => {
- /** */
- const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵprojectionDef();
- ɵɵprojection(0);
- }
- }, 1);
-
- /** content */
- const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'child');
- { ɵɵtext(1, 'content'); }
- ɵɵelementEnd();
- }
- }, 2, 0, [Child]);
-
- const parent = renderComponent(Parent);
- expect(toHtml(parent)).toEqual('content');
- });
-
- it('should project content with siblings', () => {
- /** */
- const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵprojectionDef();
- ɵɵprojection(0);
- }
- }, 1);
-
- /**
- *
- * before
- * content
- * after
- *
- */
- const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'child');
- {
- ɵɵtext(1, 'before');
- ɵɵelementStart(2, 'div');
- { ɵɵtext(3, 'content'); }
- ɵɵelementEnd();
- ɵɵtext(4, 'after');
- }
- ɵɵelementEnd();
- }
- }, 5, 0, [Child]);
-
- const parent = renderComponent(Parent);
- expect(toHtml(parent)).toEqual('beforecontent
after');
- });
-
- it('should re-project content when root.', () => {
- /**
*/
- const GrandChild = createComponent('grand-child', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵprojectionDef();
- ɵɵelementStart(0, 'div');
- { ɵɵprojection(1); }
- ɵɵelementEnd();
- }
- }, 2);
-
- /** */
- const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵprojectionDef();
- ɵɵelementStart(0, 'grand-child');
- { ɵɵprojection(1); }
- ɵɵelementEnd();
- }
- }, 2, 0, [GrandChild]);
-
- /** HelloWorld! */
- const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'child');
- {
- ɵɵelementStart(1, 'b');
- ɵɵtext(2, 'Hello');
- ɵɵelementEnd();
- ɵɵtext(3, 'World!');
- }
- ɵɵelementEnd();
- }
- }, 4, 0, [Child]);
-
- const parent = renderComponent(Parent);
- expect(toHtml(parent))
- .toEqual('HelloWorld!
');
- });
-
- it('should project components', () => {
-
- /**
*/
- const Child = createComponent('child', (rf: RenderFlags, ctx: any) => {
- if (rf & RenderFlags.Create) {
- ɵɵprojectionDef();
- ɵɵelementStart(0, 'div');
- { ɵɵprojection(1); }
- ɵɵelementEnd();
- }
- }, 2);
-
- const ProjectedComp = createComponent('projected-comp', (rf: RenderFlags, ctx: any) => {
- if (rf & RenderFlags.Create) {
- ɵɵtext(0, 'content');
- }
- }, 1);
-
- /**
- *
- *
- *
- */
- const Parent = createComponent('parent', (rf: RenderFlags, ctx: any) => {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'child');
- { ɵɵelement(1, 'projected-comp'); }
- ɵɵelementEnd();
- }
- }, 2, 0, [Child, ProjectedComp]);
-
- const parent = renderComponent(Parent);
- expect(toHtml(parent))
- .toEqual('');
- });
-
- it('should project components that have their own projection', () => {
- /**
*/
- const Child = createComponent('child', (rf: RenderFlags, ctx: any) => {
- if (rf & RenderFlags.Create) {
- ɵɵprojectionDef();
- ɵɵelementStart(0, 'div');
- { ɵɵprojection(1); }
- ɵɵelementEnd();
- }
- }, 2);
-
- /**
*/
- const ProjectedComp = createComponent('projected-comp', (rf: RenderFlags, ctx: any) => {
- if (rf & RenderFlags.Create) {
- ɵɵprojectionDef();
- ɵɵelementStart(0, 'p');
- ɵɵprojection(1);
- ɵɵelementEnd();
- }
- }, 2);
-
- /**
- *
- *
- * Some content
- * Other content
- *
- *
- */
- const Parent = createComponent('parent', (rf: RenderFlags, ctx: any) => {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'child');
- {
- ɵɵelementStart(1, 'projected-comp');
- {
- ɵɵelementStart(2, 'div');
- ɵɵtext(3, 'Some content');
- ɵɵelementEnd();
- ɵɵtext(4, 'Other content');
- }
-
- ɵɵelementEnd();
- }
- ɵɵelementEnd();
- }
- }, 5, 0, [Child, ProjectedComp]);
-
- const parent = renderComponent(Parent);
- expect(toHtml(parent))
- .toEqual(
- 'Some content
Other content ');
- });
-
it('should project containers', () => {
/**
*/
const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
@@ -802,280 +585,6 @@ describe('content projection', () => {
expect(toHtml(parent)).toEqual('');
});
- it('should project into dynamic views (with createEmbeddedView)', () => {
- /**
- * Before-
- *
- *
- *
- * -After
- */
- const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵprojectionDef();
- ɵɵtext(0, 'Before-');
- ɵɵtemplate(1, IfTemplate, 1, 0, 'ng-template', [AttributeMarker.Bindings, 'ngIf']);
- ɵɵtext(2, '-After');
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(1, 'ngIf', ɵɵbind(ctx.showing));
- }
-
- }, 3, 1, [NgIf]);
-
- function IfTemplate(rf1: RenderFlags, ctx: any) {
- if (rf1 & RenderFlags.Create) {
- ɵɵprojection(0);
- }
- }
-
- let child: {showing: boolean};
- /**
- *
- * A
- * Some text
- *
- */
- const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'child');
- {
- ɵɵelementStart(1, 'div');
- { ɵɵtext(2, 'A'); }
- ɵɵelementEnd();
- ɵɵtext(3, 'Some text');
- }
- ɵɵelementEnd();
-
- // testing
- child = getDirectiveOnNode(0);
- }
- }, 4, 0, [Child]);
-
- const fixture = new ComponentFixture(App);
- child !.showing = true;
- fixture.update();
- expect(fixture.html).toEqual('Before-A
Some text-After');
-
- child !.showing = false;
- fixture.update();
- expect(fixture.html).toEqual('Before--After');
-
- child !.showing = true;
- fixture.update();
- expect(fixture.html).toEqual('Before-A
Some text-After');
- });
-
- it('should project into dynamic views (with insertion)', () => {
- /**
- * Before-
- *
- *
- *
- * -After
- */
- const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵprojectionDef();
- ɵɵtext(0, 'Before-');
- ɵɵtemplate(1, IfTemplate, 1, 0, 'ng-template', [AttributeMarker.Bindings, 'ngIf']);
- ɵɵtext(2, '-After');
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(1, 'ngIf', ɵɵbind(ctx.showing));
- }
-
- }, 3, 1, [NgIf]);
-
- function IfTemplate(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵprojection(0);
- }
- }
-
- let child: {showing: boolean};
- /**
- *
- * A
- * Some text
- *
- */
- const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'child');
- {
- ɵɵelementStart(1, 'div');
- { ɵɵtext(2, 'A'); }
- ɵɵelementEnd();
- ɵɵtext(3, 'Some text');
- }
- ɵɵelementEnd();
-
- // testing
- child = getDirectiveOnNode(0);
- }
- }, 4, 0, [Child]);
-
- const fixture = new ComponentFixture(App);
- child !.showing = true;
- fixture.update();
- expect(fixture.html).toEqual('Before-A
Some text-After');
-
- child !.showing = false;
- fixture.update();
- expect(fixture.html).toEqual('Before--After');
-
- child !.showing = true;
- fixture.update();
- expect(fixture.html).toEqual('Before-A
Some text-After');
- });
-
- it('should project into dynamic views with specific selectors', () => {
- /**
- *
- * Before-
- *
- *
- *
- * -After
- */
- const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵprojectionDef([[['div']]]);
- ɵɵprojection(0);
- ɵɵtext(1, 'Before-');
- ɵɵtemplate(2, IfTemplate, 1, 0, 'ng-template', [AttributeMarker.Bindings, 'ngIf']);
- ɵɵtext(3, '-After');
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(2, 'ngIf', ɵɵbind(ctx.showing));
- }
-
- }, 4, 1, [NgIf]);
-
- function IfTemplate(rf1: RenderFlags) {
- if (rf1 & RenderFlags.Create) {
- ɵɵprojection(0, 1);
- }
- }
-
- let child: {showing: boolean};
- /**
- *
- * A
- * B
- *
- */
- const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'child');
- {
- ɵɵelementStart(1, 'div');
- { ɵɵtext(2, 'A'); }
- ɵɵelementEnd();
- ɵɵelementStart(3, 'span');
- { ɵɵtext(4, 'B'); }
- ɵɵelementEnd();
- }
- ɵɵelementEnd();
-
- // testing
- child = getDirectiveOnNode(0);
- }
- }, 5, 0, [Child]);
-
- const fixture = new ComponentFixture(App);
- child !.showing = true;
- fixture.update();
- expect(fixture.html).toEqual('BBefore-A
-After');
-
- child !.showing = false;
- fixture.update();
- expect(fixture.html).toEqual('BBefore--After');
-
- child !.showing = true;
- fixture.update();
- expect(fixture.html).toEqual('BBefore-A
-After');
- });
-
- it('should project if is in a template that has different declaration/insertion points',
- () => {
- let triggerDir !: Trigger;
-
- function NgTemplate(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵprojection(0);
- }
- }
-
- /**
- *
- *
- *
- */
- const Comp = createComponent(
- 'comp',
- (rf: RenderFlags, ctx: any) => {
- if (rf & RenderFlags.Create) {
- ɵɵprojectionDef();
- ɵɵtemplate(1, NgTemplate, 1, 0, 'ng-template', null, null, ɵɵtemplateRefExtractor);
- }
- },
- 2, 0, [], [],
- function(rf: RenderFlags, ctx: any) {
- /** @ViewChild(TemplateRef) template: TemplateRef */
- if (rf & RenderFlags.Create) {
- ɵɵviewQuery(TemplateRef as any, true, null);
- }
- if (rf & RenderFlags.Update) {
- let tmp: any;
- ɵɵqueryRefresh(tmp = ɵɵloadViewQuery>()) &&
- (ctx.template = tmp.first);
- }
- });
-
- class Trigger {
- // @Input()
- trigger: any;
-
- constructor(public vcr: ViewContainerRef) {}
-
- open() { this.vcr.createEmbeddedView(this.trigger.template); }
-
- static ngComponentDef = ɵɵdefineDirective({
- type: Trigger,
- selectors: [['', 'trigger', '']],
- factory: () => triggerDir = new Trigger(ɵɵdirectiveInject(ViewContainerRef as any)),
- inputs: {trigger: 'trigger'}
- });
- }
-
- /**
- *
- *
- * Some content
- *
- */
- const App = createComponent('app', (rf: RenderFlags, ctx: any) => {
- if (rf & RenderFlags.Create) {
- ɵɵelement(0, 'button', [AttributeMarker.Bindings, 'trigger']);
- ɵɵelementStart(1, 'comp', null, ['comp', '']);
- { ɵɵtext(3, 'Some content'); }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- const comp = ɵɵreference(2);
- ɵɵelementProperty(0, 'trigger', ɵɵbind(comp));
- }
- }, 4, 1, [Comp, Trigger]);
-
- const fixture = new ComponentFixture(App);
- expect(fixture.html).toEqual(``);
-
- triggerDir.open();
- expect(fixture.html).toEqual(`Some content`);
- });
-
it('should project nodes into the last ng-content', () => {
/**
*
@@ -1172,52 +681,6 @@ describe('content projection', () => {
expect(toHtml(parent)).toEqual('content
');
});
- // https://stackblitz.com/edit/angular-ceqmnw?file=src%2Fapp%2Fapp.component.ts
- it('should project nodes into the last ng-content unrolled by ngFor', () => {
- const items = [1, 2];
-
- /**
-
- ({{index}}):
-
- */
- const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵprojectionDef();
- { ɵɵtemplate(0, ForTemplate, 3, 1, 'div', [AttributeMarker.Template, 'ngFor', 'ngForOf']); }
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(0, 'ngForOf', ɵɵbind(items));
- }
- }, 1, 1, [NgForOf]);
-
- function ForTemplate(rf1: RenderFlags, ctx: {index: number}) {
- if (rf1 & RenderFlags.Create) {
- ɵɵelementStart(0, 'div');
- ɵɵtext(1);
- ɵɵprojection(2);
- ɵɵelementEnd();
- }
- if (rf1 & RenderFlags.Update) {
- ɵɵtextBinding(1, ɵɵinterpolation1('(', ctx.index, '):'));
- }
- }
-
- /**
- * content
- */
- const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'child');
- { ɵɵtext(1, 'content'); }
- ɵɵelementEnd();
- }
- }, 2, 0, [Child]);
-
- const parent = renderComponent(Parent);
- expect(toHtml(parent)).toEqual('(0):
(1):content
');
- });
-
it('should project with multiple instances of a component with projection', () => {
const ProjectionComp = createComponent('projection-comp', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
@@ -1441,88 +904,6 @@ describe('content projection', () => {
expect(toHtml(parent)).toEqual('content');
});
- it('should handle projected containers inside other containers', () => {
- // Child content
- const NestedComp = createComponent('nested-comp', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'div');
- ɵɵtext(1, 'Child content');
- ɵɵelementEnd();
- }
- }, 2, 0, []);
-
- //
- const RootComp = createComponent('root-comp', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵprojectionDef();
- ɵɵprojection(0);
- }
- }, 1, 0, []);
-
- //
- //
- //
- //
- //
- function MyApp_ng_container_1_child_comp_1_Template(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelement(0, 'nested-comp');
- }
- }
- function MyApp_ng_container_1_Template(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementContainerStart(0);
- ɵɵtemplate(
- 1, MyApp_ng_container_1_child_comp_1_Template, 1, 0, 'nested-comp',
- [AttributeMarker.Template, 'ngIf']);
- ɵɵelementContainerEnd();
- }
- if (rf & RenderFlags.Update) {
- const last_r2 = ctx.last;
- ɵɵelementProperty(1, 'ngIf', ɵɵbind(!last_r2));
- }
- }
- let myAppInstance: MyApp;
- class MyApp {
- items = [1, 2];
-
- static ngComponentDef = ɵɵdefineComponent({
- type: MyApp,
- selectors: [['', 'my-app', '']],
- factory: () => myAppInstance = new MyApp(),
- consts: 2,
- vars: 1,
- template: function MyApp_Template(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'root-comp');
- ɵɵtemplate(
- 1, MyApp_ng_container_1_Template, 2, 1, 'ng-container',
- [AttributeMarker.Template, 'ngFor', 'ngForOf']);
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(1, 'ngForOf', ɵɵbind(ctx.items));
- }
- },
- directives: [NgForOf, NgIf, NestedComp, RootComp]
- });
- }
- const fixture = new ComponentFixture(MyApp);
- fixture.update();
-
- // expecting # of divs to be (items.length - 1), since last element is filtered out by *ngIf,
- // this applies to all other assertions below
- expect(fixture.hostElement.querySelectorAll('div').length).toBe(1);
-
- myAppInstance !.items = [3, 4, 5];
- fixture.update();
- expect(fixture.hostElement.querySelectorAll('div').length).toBe(2);
-
- myAppInstance !.items = [6, 7, 8, 9];
- fixture.update();
- expect(fixture.hostElement.querySelectorAll('div').length).toBe(3);
- });
-
describe('with selectors', () => {
it('should project nodes using attribute selectors', () => {
@@ -1569,43 +950,6 @@ describe('content projection', () => {
'1
2
');
});
- // https://stackblitz.com/edit/angular-psokum?file=src%2Fapp%2Fapp.module.ts
- it('should project nodes where attribute selector matches a binding', () => {
- /**
- *
- */
- const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵprojectionDef([[['', 'title', '']]]);
- { ɵɵprojection(0, 1); }
- }
- }, 1);
-
- /**
- *
- * Has title
- *
- */
- const Parent = createComponent('parent', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'child');
- {
- ɵɵelementStart(1, 'span', [AttributeMarker.Bindings, 'title']);
- { ɵɵtext(2, 'Has title'); }
- ɵɵelementEnd();
- }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(1, 'title', ɵɵbind('Some title'));
- }
- }, 3, 1, [Child]);
-
- const fixture = new ComponentFixture(Parent);
- expect(fixture.html).toEqual('Has title');
-
- });
-
it('should project nodes using class selectors', () => {
/**
*
@@ -1991,54 +1335,6 @@ describe('content projection', () => {
const parent = renderComponent(Parent);
expect(toHtml(parent)).toEqual('should project
');
});
-
- it('should match selectors against projected containers', () => {
-
- /**
- *
- *
- *
- */
- const Child = createComponent('child', function(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵprojectionDef([[['div']]]);
- ɵɵelementStart(0, 'span');
- { ɵɵprojection(1, 1); }
- ɵɵelementEnd();
- }
- }, 2);
-
- function IfTemplate(rf: RenderFlags, ctx: any) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'div');
- { ɵɵtext(1, 'content'); }
- ɵɵelementEnd();
- }
- }
-
- /**
- *
- * content
- *
- */
- const Parent = createComponent('parent', function(rf: RenderFlags, ctx: {value: any}) {
- if (rf & RenderFlags.Create) {
- ɵɵelementStart(0, 'child');
- { ɵɵtemplate(1, IfTemplate, 2, 0, 'div', [AttributeMarker.Template, 'ngIf']); }
- ɵɵelementEnd();
- }
- if (rf & RenderFlags.Update) {
- ɵɵelementProperty(1, 'ngIf', ɵɵbind(ctx.value));
- }
- }, 2, 1, [Child, NgIf]);
-
-
- const fixture = new ComponentFixture(Parent);
- fixture.component.value = true;
- fixture.update();
- expect(fixture.html).toEqual('content
');
- });
-
});
});