Angular Ivy,一个文本节点如何指向它的 ng-template
Angular Ivy, how a text node points to its ng-template
我需要在测试中发现 tpl1
的文本节点在呈现后属于 ng-template
。
1
<ng-template tpl>
tpl1
</ng-template>
2
如果在渲染后找到 tpl1
的 debugNode,那么它的父节点指向 component
的节点,但是 我想确保 tpl1
的 debugNode =13=] 派生自 ng-template
.
到目前为止,我能够在经典模式下做到这一点,但不能在 ivy.
中找到一种方法来做到这一点
- a link to stackblitz in classic(作品):https://stackblitz.com/edit/github-5wg14l-b39rck?file=src%2Ftest.spec.ts
下面有一个最小示例,任何解决方案(不仅是 elDef 和 tNode)都适用于我。
import {Component, DebugNode, Directive, TemplateRef, VERSION, ViewChild, ViewContainerRef} from '@angular/core';
import {TestBed} from "@angular/core/testing";
@Directive({
selector: '[tpl]',
})
class TplDirective {
public constructor(public readonly tpl: TemplateRef<any>) {}
}
@Component({
selector: 'target',
template: `
1
<ng-template tpl>
tpl1
</ng-template>
2
`,
})
class TargetComponent {
@ViewChild(TplDirective, {
read: TemplateRef,
}) public readonly tpl?: TemplateRef<any>;
@ViewChild(TplDirective, {
read: ViewContainerRef,
}) public readonly vcr?: ViewContainerRef;
}
describe('issue-289', () => {
beforeEach(() => TestBed.configureTestingModule({
declarations: [TplDirective, TargetComponent],
}).compileComponents());
fit('finds right parent in ivy', () => {
const fixture = TestBed.createComponent(TargetComponent);
fixture.detectChanges();
const componentEl = fixture.debugElement;
const component: TargetComponent = componentEl.componentInstance;
// check that only defaults have been rendered
expect (componentEl.childNodes.length).toEqual(3);
const [txtEl1, tplEl, txtEl2] = componentEl.childNodes;
expect(txtEl1.nativeNode.nodeName).toEqual('#text');
expect(tplEl.nativeNode.nodeName).toEqual('#comment');
expect(txtEl2.nativeNode.nodeName).toEqual('#text');
// rendering the template
component.vcr.createEmbeddedView(component.tpl);
fixture.detectChanges();
// looking for the new element
expect (componentEl.childNodes.length).toEqual(4);
const txtTplEl = componentEl.childNodes.find(el => el !== txtEl1 && el !== tplEl && el !== txtEl2);
expect(txtTplEl.nativeNode.nodeName).toEqual('#text');
// getting internal node, 1st is classic, 2nd is ivy
const tplElNode = (tplEl.injector as any).elDef || (tplEl.injector as any)._tNode;
expect(tplElNode).toBeDefined();
// FIXME find how txtTplEl points to tplEl
// in classic (not ivy) it works like that
const txtTplNode = (txtTplEl as any)._debugContext?.view?.parentNodeDef;
// should succeed
expect(txtTplNode).toEqual(tplElNode);
});
});
这样检查怎么样
const view = component.vcr.createEmbeddedView(component.tpl);
/\
||
assign to variable
expect(view.rootNodes.includes(txtTplEl.nativeNode)).toBeTruthy();
它不涉及私有 API 并且应该在两个版本中都有效。
我需要在测试中发现 tpl1
的文本节点在呈现后属于 ng-template
。
1
<ng-template tpl>
tpl1
</ng-template>
2
如果在渲染后找到 tpl1
的 debugNode,那么它的父节点指向 component
的节点,但是 我想确保 tpl1
的 debugNode =13=] 派生自 ng-template
.
到目前为止,我能够在经典模式下做到这一点,但不能在 ivy.
中找到一种方法来做到这一点- a link to stackblitz in classic(作品):https://stackblitz.com/edit/github-5wg14l-b39rck?file=src%2Ftest.spec.ts
下面有一个最小示例,任何解决方案(不仅是 elDef 和 tNode)都适用于我。
import {Component, DebugNode, Directive, TemplateRef, VERSION, ViewChild, ViewContainerRef} from '@angular/core';
import {TestBed} from "@angular/core/testing";
@Directive({
selector: '[tpl]',
})
class TplDirective {
public constructor(public readonly tpl: TemplateRef<any>) {}
}
@Component({
selector: 'target',
template: `
1
<ng-template tpl>
tpl1
</ng-template>
2
`,
})
class TargetComponent {
@ViewChild(TplDirective, {
read: TemplateRef,
}) public readonly tpl?: TemplateRef<any>;
@ViewChild(TplDirective, {
read: ViewContainerRef,
}) public readonly vcr?: ViewContainerRef;
}
describe('issue-289', () => {
beforeEach(() => TestBed.configureTestingModule({
declarations: [TplDirective, TargetComponent],
}).compileComponents());
fit('finds right parent in ivy', () => {
const fixture = TestBed.createComponent(TargetComponent);
fixture.detectChanges();
const componentEl = fixture.debugElement;
const component: TargetComponent = componentEl.componentInstance;
// check that only defaults have been rendered
expect (componentEl.childNodes.length).toEqual(3);
const [txtEl1, tplEl, txtEl2] = componentEl.childNodes;
expect(txtEl1.nativeNode.nodeName).toEqual('#text');
expect(tplEl.nativeNode.nodeName).toEqual('#comment');
expect(txtEl2.nativeNode.nodeName).toEqual('#text');
// rendering the template
component.vcr.createEmbeddedView(component.tpl);
fixture.detectChanges();
// looking for the new element
expect (componentEl.childNodes.length).toEqual(4);
const txtTplEl = componentEl.childNodes.find(el => el !== txtEl1 && el !== tplEl && el !== txtEl2);
expect(txtTplEl.nativeNode.nodeName).toEqual('#text');
// getting internal node, 1st is classic, 2nd is ivy
const tplElNode = (tplEl.injector as any).elDef || (tplEl.injector as any)._tNode;
expect(tplElNode).toBeDefined();
// FIXME find how txtTplEl points to tplEl
// in classic (not ivy) it works like that
const txtTplNode = (txtTplEl as any)._debugContext?.view?.parentNodeDef;
// should succeed
expect(txtTplNode).toEqual(tplElNode);
});
});
这样检查怎么样
const view = component.vcr.createEmbeddedView(component.tpl);
/\
||
assign to variable
expect(view.rootNodes.includes(txtTplEl.nativeNode)).toBeTruthy();
它不涉及私有 API 并且应该在两个版本中都有效。