Skip to content

Commit

Permalink
fix(core): incorrectly throwing error for self-referencing component (#…
Browse files Browse the repository at this point in the history
…50559)

Components are implied to be self-referencing, but if they explicitly set themselves in the `imports` array, they would throw an error because we weren't filtering them out.

Fixes #50525.

PR Close #50559
  • Loading branch information
crisbeto authored and alxhub committed Jun 6, 2023
1 parent d55276a commit 79a706c
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 3 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/render3/jit/directive.ts
Expand Up @@ -245,7 +245,7 @@ function getStandaloneDefFunctions(type: Type<any>, imports: Type<any>[]): {
// Standalone components are always able to self-reference, so include the component's own
// definition in its `directiveDefs`.
cachedDirectiveDefs = [getComponentDef(type)!];
const seen = new Set<Type<unknown>>();
const seen = new Set<Type<unknown>>([type]);

This comment has been minimized.

Copy link
@fadyashraf89

fadyashraf89 Jun 6, 2023

Sho8l meya el meya w 7aga a5er 3azama allah ynawar ya regala


for (const rawDep of imports) {
ngDevMode && verifyStandaloneImport(rawDep, type);
Expand Down
66 changes: 64 additions & 2 deletions packages/core/test/acceptance/component_spec.ts
Expand Up @@ -6,8 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/

import {DOCUMENT} from '@angular/common';
import {ApplicationRef, Component, ComponentRef, createComponent, createEnvironmentInjector, Directive, ElementRef, EmbeddedViewRef, EnvironmentInjector, inject, Injectable, InjectionToken, Injector, Input, NgModule, OnDestroy, reflectComponentType, Renderer2, Type, ViewChild, ViewContainerRef, ViewEncapsulation, ɵsetDocument} from '@angular/core';
import {DOCUMENT, NgIf} from '@angular/common';
import {ApplicationRef, Component, ComponentRef, createComponent, createEnvironmentInjector, Directive, ElementRef, EmbeddedViewRef, EnvironmentInjector, forwardRef, inject, Injectable, InjectionToken, Injector, Input, NgModule, OnDestroy, reflectComponentType, Renderer2, Type, ViewChild, ViewContainerRef, ViewEncapsulation, ɵsetDocument} from '@angular/core';
import {stringifyForError} from '@angular/core/src/render3/util/stringify_utils';
import {TestBed} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/src/matchers';
Expand Down Expand Up @@ -400,6 +400,68 @@ describe('component', () => {
.toThrowError(
/NG0300: Multiple components match node with tagname comp: CompA and CompB/);
});

it('should not throw if a standalone component imports itself', () => {
@Component({
selector: 'comp',
template: '<comp *ngIf="recurse"/>hello',
standalone: true,
imports: [Comp, NgIf]
})
class Comp {
@Input() recurse = false;
}

@Component({
template: '<comp [recurse]="true"/>',
standalone: true,
imports: [Comp],
})
class App {
}

let textContent = '';

expect(() => {
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
textContent = fixture.nativeElement.textContent.trim();
}).not.toThrow();

// Ensure that the component actually rendered.
expect(textContent).toBe('hellohello');
});

it('should not throw if a standalone component imports itself using a forwardRef', () => {
@Component({
selector: 'comp',
template: '<comp *ngIf="recurse"/>hello',
standalone: true,
imports: [forwardRef(() => Comp), NgIf]
})
class Comp {
@Input() recurse = false;
}

@Component({
template: '<comp [recurse]="true"/>',
standalone: true,
imports: [Comp],
})
class App {
}

let textContent = '';

expect(() => {
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
textContent = fixture.nativeElement.textContent.trim();
}).not.toThrow();

// Ensure that the component actually rendered.
expect(textContent).toBe('hellohello');
});
});

it('should use a new ngcontent attribute for child elements created w/ Renderer2', () => {
Expand Down

0 comments on commit 79a706c

Please sign in to comment.