In my Angular2 module I've specified an array of components in the entryComponents property like this:
#NgModule({
// ...
entryComponents: [ComponentA, ComponentB]
// ...
})
export class AppModule { }
In a component I want to access this list of entryComponents. Something like this:
import { Component } from '#angular/core';
#Component({
selector: 'my-selector',
// ...
})
export class MyComponent{
// Something like this:
constructor(private moduleRef: ModuleRef){
console.log(moduleRef.entryComponents);
}
}
Is this possible in any way? I do not need an explicit reference to the module itself but only on the entryComponents list.
Thanks for your help!
Related
I read all presented questions stack overflow showed me, none of which solved my issue.
I'm new to Angular and I have a couple Modules and Components. I want a child module to import a component. Then have a parent module import the child module and create it's component. And yes, I have exported the Component in the child module.
I want it like so:
Parent Module
Child Module
Component (Toy)
But I get the error:
ERROR in parent/parent.module.ts(8,5): error TS2304: Cannot find name 'ToyComponent'.
I do not understand why this is not working. I would appreciate an explanation over some sample code. Thanks!
This is the relevant code:
Toy Component
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-toy',
templateUrl: './toy.component.html',
styleUrls: ['./toy.component.css']
})
export class ToyComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
Toy Component HTML
<p>
Awesome toy!
</p>
Child Module
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { ToyComponent } from './toy/toy.component';
import { ChildComponent } from './child.component';
#NgModule({
declarations: [
ToyComponent,
ChildComponent
],
imports: [
CommonModule
],
exports: [
ToyComponent
]
})
export class ChildModule { }
Parent Module
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { ChildModule } from './child/child.module';
import { ParentComponent } from './parent.component';
#NgModule({
declarations: [
ToyComponent,
ParentComponent
],
imports: [
ChildModule,
CommonModule
],
exports: [
]
})
export class ParentModule { }
Parent Component HTML
<p>
parent works! Child: Toy: <app-toy></app-toy>
</p>
Fix:
1. Remove ToyComponent from the declarations and exports of ParentModule.
2. Declare ToyComponent in your Child Module and export it.
3. Add ChildModule as an import to your parent module.
Reason:
Your ToyComponent is declared under your ChildModule. Since you use ToyComponent in your ParentModule, you need to export your ToyComponent from your ChildModule. And import the ChildModule in your ParentModule.
Problem
It looks like that the import statement for ToyComponent is missing in ParentModule which causes the error.
Fix
Since ToyComponent is added to exports in ChildModule it must
not be referenced in ParentModule
Remove ToyComponent from the
declarations-list in ParentModule
The ToyComponent is known to the ParentModule because ChildModule is added to the imports-List.
I have multiple modules say SchoolModule, UniversityModule, SharedModule
SharedModule has BaseService to which both SchoolModule and UniversityModule providers are extending
Now when I load my SchoolModule, I want BaseService should get the implementation of schoolService, and the same goes for UniversityModule
Structure
app
-- SharedModule
-- base.service
-- secret.service uses base.service
-- shared.component uses secret.service
-- SchoolModule
-- school.component uses shared.component
-- school.service
-- UniversityModule
-- university.component uses shared.component
-- university.service
StackBlitz
So how I can achieve this with Dependency Injection?
You have to declare your base service class as an abstract class with an abstract method getName()
export abstract class BaseService{
abstract getName(): string { return 'Base Service' }
}
export class SchoolService extends BaseService{
getName(): string { return 'School Service' }
}
Unfortunately, Angular2 can not inject a class from another module without get the import between modules, and if you need to lazy load it, things do not work.
There is a project that load dynamically a component from another module.
It is difficult to import this in to your project, but saves you to not code twice.
This project can be found here.
The problem is that SecretService provided is the one build with build in UniversityModule last imported module in App Module so if you want to have SecretService update with correctly BaseService you have to provide both BaseService and SecretService in university and school component something like this in school.component.ts:
import { SchoolService } from './school.service'
import { BaseService } from '../shared/base.service'
import { SecretService } from '../shared/secret.service'
#Component({
selector: 'app-school',
template: `SchoolName :: <app-shared></app-shared>`,
providers: [
{ provide: BaseService, useClass: SchoolService },
SecretService]
})
export class SchoolComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
and in university.component.ts
import { UniversityService } from './university.service'
import { BaseService } from '../shared/base.service'
import { SecretService } from '../shared/secret.service'
#Component({
selector: 'app-university',
template: `UniversityName :: <app-shared></app-shared>`,
providers: [{ provide: BaseService, useClass: UniversityService },
SecretService]
})
export class UniversityComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
But why you wanna wrap base service in SecretService instead directly use BaseService in shared component ?
Using BaseService like this in shared.component.ts
import { Component, OnInit } from '#angular/core';
import { BaseService } from './base.service'
#Component({
selector: 'app-shared',
template: `{{name}}`
})
export class SharedComponent implements OnInit {
name: string
constructor(private ss: BaseService) {
this.name = ss.getName()
}
ngOnInit() {
}
}
Using BaseService you will solve this injection problem without any workaround on SecretService
I created a core library for my project containing some components and services. I built the library with ng-packagr. In the consuming project which references the library I built my webapp containing components provided by the library. Nothing special so far. But sometimes I want a component (coming from my lib) calling a method from a Service outside of the lib. Is this possible? Can I somehow inject a service to a component which is defined inside a library?
Cheers
I've achieved this before with something like this:
Your library's service(s) should be defined as an interface rather than as a concrete implementation (as is done in OO languages quite often). If your implementing application will only sometimes want to pass in its own version of the service then you should create a Default service in your library, and use it as so:
import { Component, NgModule, ModuleWithProviders, Type, InjectionToken, Inject, Injectable } from '#angular/core';
export interface ILibService {
aFunction(): string;
}
export const LIB_SERVICE = new InjectionToken<ILibService>('LIB_SERVICE');
export interface MyLibConfig {
myService: Type<ILibService>;
}
#Injectable()
export class DefaultLibService implements ILibService {
aFunction() {
return 'default';
}
}
#Component({
// whatever
})
export class MyLibComponent {
constructor(#Inject(LIB_SERVICE) libService: ILibService) {
console.log(libService.aFunction());
}
}
#NgModule({
declarations: [MyLibComponent],
exports: [MyLibComponent]
})
export class LibModule {
static forRoot(config?: MyLibConfig): ModuleWithProviders {
return {
ngModule: LibModule,
providers: [
{ provide: LIB_SERVICE, useClass: config && config.myService || DefaultLibService }
]
};
}
}
Then in your implementing application you have the ability to pass in the optional config via your library's forRoot method (note that forRoot should only be called once per application and at the highest level possible). Note that I've marked the config parameter as optional, so you should call forRoot even if you have no config to pass.
import { NgModule, Injectable } from '#angular/core';
import { LibModule, ILibService } from 'my-lib';
#Injectable()
export class OverridingService implements ILibService {
aFunction() {
return 'overridden!';
}
}
#NgModule({
imports: [LibModule.forRoot({ myService: OverridingService })]
})
export class ImplementingModule {
}
This was from memory as I don't have the code to hand at the moment so if it doesn't work for any reason let me know.
I built a service that called lang.service.ts. What it does is simply a key: value mechanism. Whenever I need it to my component, I import it and declare it in the constructor and then I use it as {{lang('key').text}}. so far, so good.
The thing is that I've noticed that I'm gonna load it for each component, like for view-header.component.ts, view-footer.components.ts and a lot of other components. I never used Angular 1, but IIRC, I could do there something like rootScope.lang(..) and it could've accomplish what I was looking for. Is there a way to do something like that in Angular 2?
If you register your service at your root componet, all child components will have access to the service.
On your root component...
import { Component } from '#angular/core';
import { YourService } from './my-servive.service.ts';
import { ChildComponent } from './child-component.component.ts';
#Component({
selector: 'root-component',
providers: [YourService],
directives: [ChildComponent],
template: `<child-component></child-component>`
})
export class RootComponent {}
On your child component...
import { Component } from '#angular/core';
import { YourService } from './my-servive.service.ts';
#Component({
selector: 'child-component'
})
export class ChildComponent {
contructor(private myService: YourService) {}
}
Hope this help you.
Angular 2 - When injecting(importing) a service into my constructor I get a "No provider" error.
Here's my service I'm importing:
export class EnvironmentService {
public baseurl: string = "/baseurl/example/";
}
Here's my class with the error:
import {Http, Headers} from "angular2/http";
import {Injectable} from 'angular2/angular2';
import {EnvironmentService} from './environmentService';
#Injectable()
export class AuthService {
constructor(private _environmentService: EnvironmentService) {
//This is where the error is.
console.log(this._environmentService);
}
isUserLoggedIn = (): Promise<boolean> => {
return new Promise((resolve, reject) => {
resolve(true);
})
}
}
Add AuthService in app.module.ts Providers
Most likely you didn't specify EnvironmentService as a provider for your application. You can do it by passing all providers in a second argument of the bootstrap function, or using providers and viewProviders properties of the Component decorator:
bootstrap(AppComponent, [EnvironmentService /*, other providers */]);
// or
#Component({
// ... component config
providers: [EnvironmentService],
// or
viewProviders: [EnvironmentService]
})
class AppComponent { /* ... */ }
GO to the module that you want to use the EnvironmentService i.e app.module.ts or other modules.
after imports
you will see provider as an array
add the EnvironmentService
providers: [AuthService]