Repository navigation
Description
🚀 feature request
Relevant Package
This feature request is for @angular/coreDescription
When loading component lazily (or just creating component dynamically) and you don't have it declared anywhere in modules, you can't access any features from this component, unless you load them also lazily in component or you create workaround module for this specific component to specify what imports you want to use in this component.Why I need this
Main problem for me is that I have many components that are dynamically created and inserted. They are all declared in one file and then declared in also one module which has some shared module imported (This SharedModule is something I need in loaded components too). Now since I don't have to write the component in entryComponents and also it is not necessary to write it in declarations either, I want to remove this file containing the set of components.
Describe the solution you'd like
I'm not very familiar with angular source code, so I can't really make clear suggestions, but I think it will be possible since ivy now is much more dynamic to add features to component instance when calling ViewContainerRef.createComponent. So I think it would be wonderful if it was possible to set module same as caller module for created component too, of course if it isn't already declared in any of the modules (I hope ViewContainerRef somehow knows in which module opener component is declared).Describe alternatives you've considered
The way to fix my problem is to declare all of those components into their own logical modules, or create separate modules for each of the components, but that's quite extra work to do and I don't understand why this should be required when I think it will be a lot easier to give those components opener's module (Or if it is possible to somehow find workaround to add module on my own when calling createComponent please let me know how).
Activity
montella1507 commentedon Feb 20, 2020
The magic behind this is again strange like in the past with loadChildren: () => ...
It doesnt work for my lazy -loaded component and i have no idea why ..
@component({
selector: 'a-comp',
templateUrl: './a-comp.html'
})
export class AComponent{
conustrucotr(aservice: AService) {}
}
@NgModule({
imports: [],
declarations: [AComponent],
providers: [AService]
})
export class AComponentModule{
}
but my component has Injector of AppModule, and NOT AcomponentModule so i am getting error like:
R3InjectorError(AppModule)[AComponent -> AService]:
I wish angular will get rid of this unspecified magic one time..
mlc-mlapis commentedon Feb 20, 2020
@montella1507 Without a simple reproduction demo it's hard to say anything, as always. It's a long-standing evergreen, that is repeating in a lot of issues. It's probably over my imagination why it's not understandable.
montella1507 commentedon Feb 20, 2020
@mlc-mlapis it isnt understandable it behaves like black magic? I will try to prepare repro repo.
mlc-mlapis commentedon Feb 20, 2020
@montella1507 Thank you. 👍
montella1507 commentedon Feb 20, 2020
city-quiz.zip
Note:
const quizCardFactory = this.cfr.resolveComponentFactory(QuizCardComponent); const {instance} = this.quizContainer.createComponent(quizCardFactory, null, this.injector);it doesnt work even without this.injector
4) When you break code on this line:
const {instance} = this.quizContainer.createComponent(quizCardFactory, null);
you would see, that component is bound NOT TO QuizCardModule but to AppModule.
levani132 commentedon Feb 20, 2020
I'm sorry but don't you think that is kind of bug that has nothing to do with my feature request? btw @montella1507 why don't you provide it directly to component's providers? And once again please someone pay attention to my idea, or at least tell me if it is not possible to 'add' creator's imports to created component.
montella1507 commentedon Feb 20, 2020
@levani132 well i am sorry. I have created my own issue. However.. it propably doesnt work how you think as well => Component is propably not "child" of module where it is declared.
In my example lazy loaded QuizComponent is not created with QuizComponentModule.injector so your:
is little bit wrong i think, dont you?
mlc-mlapis commentedon Feb 20, 2020
@levani132 Just to confirm what you suggested:
When using
createComponent, take the current module as a default/context module for used component type? And all import relations, normally defined in an explicitly declared module, solve in run-time?levani132 commentedon Feb 20, 2020
@montella1507 So what is written there is not quite wrong, that is current behaviour and I can show you this too, also it's not about being child, rather it's about adding/injecting/importing things into component.
To say it more clearly when you declare component into ng module, what happens is that the module takes this component (which really is a class), it does what I just said adds features like components and pipes and directives and whenever this component is compiled now it knows how to use those.
When we call resolveComponentFactory and createComponent, first one takes exactly the same kind of class as the NgModule takes, now if NgModule can add features to the declared component, why will it be impossible to make createComponent(resolveComponentFactory(Component)); add those features to the component? The only reason here can be that those methods/functions doesn't know what features to add, because it may don't know what module is declarer of opener component.
If ViewContainerRef can have something like context or some extra info where createComponent can find modules/components/pipes/directives imported and used in current component, than it can do what I'm asking for.
levani132 commentedon Feb 20, 2020
Yes exactly. So what you're saying is that everything that is imported in modules are resolved in build time? And component has references to other features directly from build time? Is not it possible to add them in run time?
mlc-mlapis commentedon Feb 20, 2020
@levani132 Exactly, all that during the build process.
It is technically possible to do it in run-time, but there are a lot of combinations and edge-cases, and all of those factors complicate the code a lot and have major performance influences. This would be similar to the original
ReflectiveInjector(https://angular.io/api/core/ReflectiveInjector, depreciated in Angular 5 and will be removed in Angular 10), and I think that the reasons are still the same.levani132 commentedon Feb 20, 2020
@mlc-mlapis Maybe... I still hope someone could think about making components' classes usable without of any declaration.
jelbourn commentedon Oct 9, 2020
Tracking the main underlying concern here in #18093
angular-automatic-lock-bot commentedon Nov 9, 2020
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.