fix(ivy): inject attributes for directives on ng-template / ng-container (#25697)
PR Close #25697
This commit is contained in:
parent
0fe708ff82
commit
0386c44acc
|
@ -268,12 +268,12 @@ const componentFactoryResolver: ComponentFactoryResolver = new ComponentFactoryR
|
||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
export function injectAttribute(attrNameToInject: string): string|undefined {
|
export function injectAttribute(attrNameToInject: string): string|undefined {
|
||||||
ngDevMode && assertPreviousIsParent();
|
const lNode = getPreviousOrParentNode();
|
||||||
const lElement = getPreviousOrParentNode() as LElementNode;
|
ngDevMode && assertNodeOfPossibleTypes(
|
||||||
ngDevMode && assertNodeType(lElement, TNodeType.Element);
|
lNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer);
|
||||||
const tElement = lElement.tNode;
|
const tNode = lNode.tNode;
|
||||||
ngDevMode && assertDefined(tElement, 'expecting tNode');
|
ngDevMode && assertDefined(tNode, 'expecting tNode');
|
||||||
const attrs = tElement.attrs;
|
const attrs = tNode.attrs;
|
||||||
if (attrs) {
|
if (attrs) {
|
||||||
for (let i = 0; i < attrs.length; i = i + 2) {
|
for (let i = 0; i < attrs.length; i = i + 2) {
|
||||||
const attrName = attrs[i];
|
const attrName = attrs[i];
|
||||||
|
|
|
@ -6,19 +6,19 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ChangeDetectorRef, ElementRef, Host, InjectFlags, Optional, Self, SkipSelf, TemplateRef, ViewContainerRef, defineInjectable} from '@angular/core';
|
import {Attribute, ChangeDetectorRef, ElementRef, Host, InjectFlags, Optional, Self, SkipSelf, TemplateRef, ViewContainerRef, defineInjectable} from '@angular/core';
|
||||||
import {RenderFlags} from '@angular/core/src/render3/interfaces/definition';
|
import {RenderFlags} from '@angular/core/src/render3/interfaces/definition';
|
||||||
|
|
||||||
import {defineComponent} from '../../src/render3/definition';
|
import {defineComponent} from '../../src/render3/definition';
|
||||||
import {bloomAdd, bloomFindPossibleInjector, getOrCreateNodeInjector, injectAttribute} from '../../src/render3/di';
|
import {bloomAdd, bloomFindPossibleInjector, getOrCreateNodeInjector, injectAttribute} from '../../src/render3/di';
|
||||||
import {NgOnChangesFeature, PublicFeature, defineDirective, directiveInject, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
|
import {NgOnChangesFeature, PublicFeature, defineDirective, directiveInject, injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
|
||||||
import {bind, container, containerRefreshEnd, containerRefreshStart, createLNode, createLViewData, createTView, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, projection, projectionDef, reference, template, text, textBinding} from '../../src/render3/instructions';
|
import {bind, container, containerRefreshEnd, containerRefreshStart, createLNode, createLViewData, createTView, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, projection, projectionDef, reference, template, text, textBinding, loadDirective, elementContainerStart, elementContainerEnd} from '../../src/render3/instructions';
|
||||||
import {LInjector} from '../../src/render3/interfaces/injector';
|
import {LInjector} from '../../src/render3/interfaces/injector';
|
||||||
import {AttributeMarker, TNodeType} from '../../src/render3/interfaces/node';
|
import {AttributeMarker, TNodeType} from '../../src/render3/interfaces/node';
|
||||||
import {LViewFlags} from '../../src/render3/interfaces/view';
|
import {LViewFlags} from '../../src/render3/interfaces/view';
|
||||||
import {ViewRef} from '../../src/render3/view_ref';
|
import {ViewRef} from '../../src/render3/view_ref';
|
||||||
|
|
||||||
import {ComponentFixture, createComponent, createDirective, renderComponent, renderToHtml, toHtml} from './render_util';
|
import {ComponentFixture, createComponent, createDirective, renderComponent, toHtml} from './render_util';
|
||||||
|
|
||||||
describe('di', () => {
|
describe('di', () => {
|
||||||
describe('no dependencies', () => {
|
describe('no dependencies', () => {
|
||||||
|
@ -1207,6 +1207,23 @@ describe('di', () => {
|
||||||
|
|
||||||
describe('@Attribute', () => {
|
describe('@Attribute', () => {
|
||||||
|
|
||||||
|
class MyDirective {
|
||||||
|
exists = 'wrong' as string | undefined;
|
||||||
|
myDirective = 'wrong' as string | undefined;
|
||||||
|
constructor(
|
||||||
|
@Attribute('exist') existAttrValue: string|undefined,
|
||||||
|
@Attribute('myDirective') myDirectiveAttrValue: string|undefined) {
|
||||||
|
this.exists = existAttrValue;
|
||||||
|
this.myDirective = myDirectiveAttrValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ngDirectiveDef = defineDirective({
|
||||||
|
type: MyDirective,
|
||||||
|
selectors: [['', 'myDirective', '']],
|
||||||
|
factory: () => new MyDirective(injectAttribute('exist'), injectAttribute('myDirective'))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
it('should inject attribute', () => {
|
it('should inject attribute', () => {
|
||||||
let exist = 'wrong' as string | undefined;
|
let exist = 'wrong' as string | undefined;
|
||||||
let nonExist = 'wrong' as string | undefined;
|
let nonExist = 'wrong' as string | undefined;
|
||||||
|
@ -1224,6 +1241,48 @@ describe('di', () => {
|
||||||
expect(nonExist).toEqual(undefined);
|
expect(nonExist).toEqual(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// https://stackblitz.com/edit/angular-scawyi?file=src%2Fapp%2Fapp.component.ts
|
||||||
|
it('should inject attributes on <ng-template>', () => {
|
||||||
|
let myDirectiveInstance: MyDirective;
|
||||||
|
|
||||||
|
/* <ng-template myDirective="initial" exist="existValue" other="ignore"></ng-template>*/
|
||||||
|
const MyApp = createComponent('my-app', function(rf: RenderFlags, ctx: any) {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
template(
|
||||||
|
0, null, 0, 0, null,
|
||||||
|
['myDirective', 'initial', 'exist', 'existValue', 'other', 'ignore']);
|
||||||
|
}
|
||||||
|
if (rf & RenderFlags.Update) {
|
||||||
|
myDirectiveInstance = loadDirective(0);
|
||||||
|
}
|
||||||
|
}, 1, 0, [MyDirective]);
|
||||||
|
|
||||||
|
new ComponentFixture(MyApp);
|
||||||
|
expect(myDirectiveInstance !.exists).toEqual('existValue');
|
||||||
|
expect(myDirectiveInstance !.myDirective).toEqual('initial');
|
||||||
|
});
|
||||||
|
|
||||||
|
// https://stackblitz.com/edit/angular-scawyi?file=src%2Fapp%2Fapp.component.ts
|
||||||
|
it('should inject attributes on <ng-container>', () => {
|
||||||
|
let myDirectiveInstance: MyDirective;
|
||||||
|
|
||||||
|
/* <ng-container myDirective="initial" exist="existValue" other="ignore"></ng-container>*/
|
||||||
|
const MyApp = createComponent('my-app', function(rf: RenderFlags, ctx: any) {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
elementContainerStart(
|
||||||
|
0, ['myDirective', 'initial', 'exist', 'existValue', 'other', 'ignore']);
|
||||||
|
elementContainerEnd();
|
||||||
|
}
|
||||||
|
if (rf & RenderFlags.Update) {
|
||||||
|
myDirectiveInstance = loadDirective(0);
|
||||||
|
}
|
||||||
|
}, 1, 0, [MyDirective]);
|
||||||
|
|
||||||
|
new ComponentFixture(MyApp);
|
||||||
|
expect(myDirectiveInstance !.exists).toEqual('existValue');
|
||||||
|
expect(myDirectiveInstance !.myDirective).toEqual('initial');
|
||||||
|
});
|
||||||
|
|
||||||
// https://stackblitz.com/edit/angular-8ytqkp?file=src%2Fapp%2Fapp.component.ts
|
// https://stackblitz.com/edit/angular-8ytqkp?file=src%2Fapp%2Fapp.component.ts
|
||||||
it('should not inject attributes representing bindings and outputs', () => {
|
it('should not inject attributes representing bindings and outputs', () => {
|
||||||
let exist = 'wrong' as string | undefined;
|
let exist = 'wrong' as string | undefined;
|
||||||
|
|
Loading…
Reference in New Issue