feat(ivy): add ng-reflect debug text for containers (#27350)
PR Close #27350
This commit is contained in:
parent
20cef5078d
commit
1279a503a1
|
@ -16,7 +16,6 @@ import {Sanitizer} from '../sanitization/security';
|
||||||
import {StyleSanitizeFn} from '../sanitization/style_sanitizer';
|
import {StyleSanitizeFn} from '../sanitization/style_sanitizer';
|
||||||
import {Type} from '../type';
|
import {Type} from '../type';
|
||||||
import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../util/ng_reflect';
|
import {normalizeDebugBindingName, normalizeDebugBindingValue} from '../util/ng_reflect';
|
||||||
|
|
||||||
import {assertDataInRange, assertDefined, assertEqual, assertHasParent, assertLessThan, assertNotEqual, assertPreviousIsParent} from './assert';
|
import {assertDataInRange, assertDefined, assertEqual, assertHasParent, assertLessThan, assertNotEqual, assertPreviousIsParent} from './assert';
|
||||||
import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4} from './bindings';
|
import {bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4} from './bindings';
|
||||||
import {attachPatchData, getComponentViewByInstance} from './context_discovery';
|
import {attachPatchData, getComponentViewByInstance} from './context_discovery';
|
||||||
|
@ -30,7 +29,7 @@ import {AttributeMarker, InitialInputData, InitialInputs, LocalRefExtractor, Pro
|
||||||
import {PlayerFactory} from './interfaces/player';
|
import {PlayerFactory} from './interfaces/player';
|
||||||
import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
|
import {CssSelectorList, NG_PROJECT_AS_ATTR_NAME} from './interfaces/projection';
|
||||||
import {LQueries} from './interfaces/query';
|
import {LQueries} from './interfaces/query';
|
||||||
import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, RendererFactory3, isProceduralRenderer} from './interfaces/renderer';
|
import {ProceduralRenderer3, RComment, RElement, RText, Renderer3, RendererFactory3, isProceduralRenderer} from './interfaces/renderer';
|
||||||
import {SanitizerFn} from './interfaces/sanitization';
|
import {SanitizerFn} from './interfaces/sanitization';
|
||||||
import {StylingIndex} from './interfaces/styling';
|
import {StylingIndex} from './interfaces/styling';
|
||||||
import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LView, LViewFlags, NEXT, OpaqueViewState, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, RootContext, RootContextFlags, SANITIZER, TAIL, TVIEW, TView} from './interfaces/view';
|
import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, HOST_NODE, INJECTOR, LView, LViewFlags, NEXT, OpaqueViewState, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, RootContext, RootContextFlags, SANITIZER, TAIL, TVIEW, TView} from './interfaces/view';
|
||||||
|
@ -957,8 +956,10 @@ export function elementProperty<T>(
|
||||||
if (inputData && (dataValue = inputData[propName])) {
|
if (inputData && (dataValue = inputData[propName])) {
|
||||||
setInputsForProperty(lView, dataValue, value);
|
setInputsForProperty(lView, dataValue, value);
|
||||||
if (isComponent(tNode)) markDirtyIfOnPush(lView, index + HEADER_OFFSET);
|
if (isComponent(tNode)) markDirtyIfOnPush(lView, index + HEADER_OFFSET);
|
||||||
if (ngDevMode && tNode.type === TNodeType.Element) {
|
if (ngDevMode) {
|
||||||
setNgReflectProperties(lView, element as RElement, propName, value);
|
if (tNode.type === TNodeType.Element || tNode.type === TNodeType.Container) {
|
||||||
|
setNgReflectProperties(lView, element, tNode.type, propName, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (tNode.type === TNodeType.Element) {
|
} else if (tNode.type === TNodeType.Element) {
|
||||||
const renderer = lView[RENDERER];
|
const renderer = lView[RENDERER];
|
||||||
|
@ -1031,12 +1032,23 @@ function setInputsForProperty(lView: LView, inputs: PropertyAliasValue, value: a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setNgReflectProperties(lView: LView, element: RElement, propName: string, value: any) {
|
function setNgReflectProperties(
|
||||||
|
lView: LView, element: RElement | RComment, type: TNodeType, propName: string, value: any) {
|
||||||
const renderer = lView[RENDERER];
|
const renderer = lView[RENDERER];
|
||||||
const attrName = normalizeDebugBindingName(propName);
|
const attrName = normalizeDebugBindingName(propName);
|
||||||
const debugValue = normalizeDebugBindingValue(value);
|
const debugValue = normalizeDebugBindingValue(value);
|
||||||
isProceduralRenderer(renderer) ? renderer.setAttribute(element, attrName, debugValue) :
|
if (type === TNodeType.Element) {
|
||||||
element.setAttribute(attrName, debugValue);
|
isProceduralRenderer(renderer) ?
|
||||||
|
renderer.setAttribute((element as RElement), attrName, debugValue) :
|
||||||
|
(element as RElement).setAttribute(attrName, debugValue);
|
||||||
|
} else if (value !== undefined) {
|
||||||
|
const value = `bindings=${JSON.stringify({[attrName]: debugValue}, null, 2)}`;
|
||||||
|
if (isProceduralRenderer(renderer)) {
|
||||||
|
renderer.setValue((element as RComment), value);
|
||||||
|
} else {
|
||||||
|
(element as RComment).textContent = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -83,7 +83,7 @@ export interface ProceduralRenderer3 {
|
||||||
flags?: RendererStyleFlags2|RendererStyleFlags3): void;
|
flags?: RendererStyleFlags2|RendererStyleFlags3): void;
|
||||||
removeStyle(el: RElement, style: string, flags?: RendererStyleFlags2|RendererStyleFlags3): void;
|
removeStyle(el: RElement, style: string, flags?: RendererStyleFlags2|RendererStyleFlags3): void;
|
||||||
setProperty(el: RElement, name: string, value: any): void;
|
setProperty(el: RElement, name: string, value: any): void;
|
||||||
setValue(node: RText, value: string): void;
|
setValue(node: RText|RComment, value: string): void;
|
||||||
|
|
||||||
// TODO(misko): Deprecate in favor of addEventListener/removeEventListener
|
// TODO(misko): Deprecate in favor of addEventListener/removeEventListener
|
||||||
listen(target: RNode, eventName: string, callback: (event: any) => boolean | void): () => void;
|
listen(target: RNode, eventName: string, callback: (event: any) => boolean | void): () => void;
|
||||||
|
@ -152,7 +152,7 @@ export interface RDomTokenList {
|
||||||
|
|
||||||
export interface RText extends RNode { textContent: string|null; }
|
export interface RText extends RNode { textContent: string|null; }
|
||||||
|
|
||||||
export interface RComment extends RNode {}
|
export interface RComment extends RNode { textContent: string|null; }
|
||||||
|
|
||||||
// Note: This hack is necessary so we don't erroneously get a circular dependency
|
// Note: This hack is necessary so we don't erroneously get a circular dependency
|
||||||
// failure based on types.
|
// failure based on types.
|
||||||
|
|
|
@ -1688,7 +1688,7 @@ function declareTests(config?: {useJit: boolean}) {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('logging property updates', () => {
|
describe('logging property updates', () => {
|
||||||
fixmeIvy('FW-664: ng-reflect-* is not supported')
|
fixmeIvy('FW-587: Inputs with aliases in component decorators don\'t work')
|
||||||
.it('should reflect property values as attributes', () => {
|
.it('should reflect property values as attributes', () => {
|
||||||
TestBed.configureTestingModule({declarations: [MyComp, MyDir]});
|
TestBed.configureTestingModule({declarations: [MyComp, MyDir]});
|
||||||
const template = '<div>' +
|
const template = '<div>' +
|
||||||
|
@ -1712,21 +1712,19 @@ function declareTests(config?: {useJit: boolean}) {
|
||||||
expect(getDOM().getInnerHTML(fixture.nativeElement)).toContain('ng-reflect-test_="hello"');
|
expect(getDOM().getInnerHTML(fixture.nativeElement)).toContain('ng-reflect-test_="hello"');
|
||||||
});
|
});
|
||||||
|
|
||||||
fixmeIvy('FW-664: ng-reflect-* is not supported')
|
it('should reflect property values on template comments', () => {
|
||||||
.it('should reflect property values on template comments', () => {
|
const fixture =
|
||||||
const fixture =
|
TestBed.configureTestingModule({declarations: [MyComp]})
|
||||||
TestBed.configureTestingModule({declarations: [MyComp]})
|
.overrideComponent(
|
||||||
.overrideComponent(
|
MyComp, {set: {template: '<ng-template [ngIf]="ctxBoolProp"></ng-template>'}})
|
||||||
MyComp,
|
.createComponent(MyComp);
|
||||||
{set: {template: '<ng-template [ngIf]="ctxBoolProp"></ng-template>'}})
|
|
||||||
.createComponent(MyComp);
|
|
||||||
|
|
||||||
fixture.componentInstance.ctxBoolProp = true;
|
fixture.componentInstance.ctxBoolProp = true;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
expect(getDOM().getInnerHTML(fixture.nativeElement))
|
expect(getDOM().getInnerHTML(fixture.nativeElement))
|
||||||
.toContain('"ng\-reflect\-ng\-if"\: "true"');
|
.toContain('"ng\-reflect\-ng\-if"\: "true"');
|
||||||
});
|
});
|
||||||
|
|
||||||
// also affected by FW-587: Inputs with aliases in component decorators don't work
|
// also affected by FW-587: Inputs with aliases in component decorators don't work
|
||||||
fixmeIvy('FW-664: ng-reflect-* is not supported')
|
fixmeIvy('FW-664: ng-reflect-* is not supported')
|
||||||
|
|
|
@ -273,16 +273,19 @@ export function toHtml<T>(componentOrElement: T | RElement, keepNgReflect = fals
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element) {
|
if (element) {
|
||||||
let html = stringifyElement(element)
|
let html = stringifyElement(element);
|
||||||
.replace(/^<div host="">(.*)<\/div>$/, '$1')
|
|
||||||
.replace(/^<div fixture="mark">(.*)<\/div>$/, '$1')
|
|
||||||
.replace(/^<div host="mark">(.*)<\/div>$/, '$1')
|
|
||||||
.replace(' style=""', '')
|
|
||||||
.replace(/<!--container-->/g, '')
|
|
||||||
.replace(/<!--ng-container-->/g, '');
|
|
||||||
if (!keepNgReflect) {
|
if (!keepNgReflect) {
|
||||||
html = html.replace(/\sng-reflect-\S*="[^"]*"/g, '');
|
html = html.replace(/\sng-reflect-\S*="[^"]*"/g, '')
|
||||||
|
.replace(/<!--bindings=\{(\W.*\W\s*)?\}-->/g, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html = html.replace(/^<div host="">(.*)<\/div>$/, '$1')
|
||||||
|
.replace(/^<div fixture="mark">(.*)<\/div>$/, '$1')
|
||||||
|
.replace(/^<div host="mark">(.*)<\/div>$/, '$1')
|
||||||
|
.replace(' style=""', '')
|
||||||
|
.replace(/<!--container-->/g, '')
|
||||||
|
.replace(/<!--ng-container-->/g, '');
|
||||||
return html;
|
return html;
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return '';
|
||||||
|
|
|
@ -131,16 +131,15 @@ let lastCreatedRenderer: Renderer2;
|
||||||
checkSetters(fixture.componentRef, fixture.debugElement.children[0].nativeElement);
|
checkSetters(fixture.componentRef, fixture.debugElement.children[0].nativeElement);
|
||||||
});
|
});
|
||||||
|
|
||||||
fixmeIvy('#FW-664 ng-reflect-* is not supported')
|
it('should update any template comment property/attributes', () => {
|
||||||
.it('should update any template comment property/attributes', () => {
|
const fixture =
|
||||||
const fixture =
|
TestBed.overrideTemplate(MyComp2, '<ng-container *ngIf="ctxBoolProp"></ng-container>')
|
||||||
TestBed.overrideTemplate(MyComp2, '<ng-container *ngIf="ctxBoolProp"></ng-container>')
|
.createComponent(MyComp2);
|
||||||
.createComponent(MyComp2);
|
fixture.componentInstance.ctxBoolProp = true;
|
||||||
fixture.componentInstance.ctxBoolProp = true;
|
fixture.detectChanges();
|
||||||
fixture.detectChanges();
|
const el = getRenderElement(fixture.nativeElement);
|
||||||
const el = getRenderElement(fixture.nativeElement);
|
expect(getDOM().getInnerHTML(el)).toContain('"ng-reflect-ng-if": "true"');
|
||||||
expect(getDOM().getInnerHTML(el)).toContain('"ng-reflect-ng-if": "true"');
|
});
|
||||||
});
|
|
||||||
|
|
||||||
it('should add and remove fragments', () => {
|
it('should add and remove fragments', () => {
|
||||||
const fixture =
|
const fixture =
|
||||||
|
|
Loading…
Reference in New Issue