Angular: Component from a shared module not being recognized - javascript

I have an app with 2 modules so far: "Shared" and "Web".
All my components in web are working fine. I just created a simple component in the Shared module since I plan to re-use it throughout the app:
import { Component, Input, OnInit } from '#angular/core';
#Component({
selector: 'pb-ds-pluginstable',
templateUrl: './pluginstable.component.html',
styleUrls: ['./pluginstable.component.scss']
})
export class PluginstableComponent implements OnInit {
#Input() name: string;
#Input() version: string;
#Input() link: string;
constructor() {}
ngOnInit() {}
}
This is imported into the shared module, and exported:
...other imports...
import { PluginstableComponent } from './pluginstable/pluginstable.component';
#NgModule({
imports: [
CommonModule,
RouterModule,
NgbModule
],
declarations: [HeaderComponent, FooterComponent, HeaderShadowDirective, PluginstableComponent],
exports: [HeaderComponent, FooterComponent, HeaderShadowDirective, PluginstableComponent]
})
export class SharedModule { }
But when I use this in a component's template in the Web module, like this:
<pb-ds-pluginstable name="foo" version="2.2.2" link="bar"></pb-ds-pluginstable>
I get an error that the component is not recognized:
core.es5.js:1020 ERROR Error: Uncaught (in promise): Error: Template parse errors:
'pb-ds-pluginstable' is not a known element:
1. If 'pb-ds-pluginstable' is an Angular component, then verify that it is part of this module.
2. If 'pb-ds-pluginstable' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '#NgModule.schemas' of this component to suppress this message. ("
</section>
[ERROR ->]<pb-ds-pluginstable name="foo" version="2.2.2" link="bar"></pb-ds-pluginstable>
What am I missing here?

You need also to import the SharedModule in that(not parent, not child, exact that module) module, where you want to use it's exported elements
#NgModule({
imports: [
SharedModule,
...
]
})
export class YourModule { }

I asume that you are not importing the shared module into the web module. Most likely you added the import only into the app module

in shared module
you have to export that component.
suppose you have moduleone module which has component componentone you want to add moduleone in shared module moduleshared, which will be added into moduletwo.
I have to export component in moduleshared
that was the problem.
I added my module moduleone in moduleshared but forgot to import, once I added then its available in other component of moduletwo

Related

How to inject a nestjs service into another service when both belong to the same module?

I have the following scenario in NestJS:
// user.service.ts
#Injectable()
export class UserService {
constructor(
private readonly userRepository: UserRepository,
private readonly userProfileService: UserProfileService,
) {}
}
// user-profile.service.ts
#Injectable()
export class UserProfileService {
constructor(
private readonly userProfileRepository: UserProfileRepository,
) {}
}
// user.module.ts
#Module({
imports: [DataRepositoryModule], // Required for the repository dependencies
providers: [UserService, UserProfileService],
exports: [UserService, UserProfileService],
})
export class UserModule {}
However, when I try to use the UserService inside a controller from another module, I get the following error:
Nest can't resolve dependencies of the UserService (UserRepository, ?). Please make sure that the argument dependency at index [1] is available in the UserModule context.
Potential solutions:
- If dependency is a provider, is it part of the current UserModule?
- If dependency is exported from a separate #Module, is that module imported within UserModule?
#Module({
imports: [ /* the Module containing dependency */ ]
})
Controller code:
#Controller()
export class UserController {
constructor(private readonly userService: UserService) {}
}
Controller module:
#Module({
imports: [],
providers: [],
controllers: [UserController],
})
export class UserManagementModule {}
Main app.module.ts:
#Module({
imports: [
UserManagementModule,
UserModule,
DataRepositoryModule.forRoot(),
],
controllers: [],
providers: [],
})
export class AppModule {}
I'm confused because I'm doing exactly what the error suggests, adding both services inside the providers array (UserModule). What could I be missing?
From your error, it looks like there's a circular dependency between your file imports. Check to make sure that you don't have a circular import chain going on (i.e. ServiceA imports ServiceB imports ServiceA or ServiceA imports ModuleA imports ServiceB imports ServiceA). This can especially become common common when using barrel files inside the same module.

dynamically render a component in lazy loaded module with AOT throws cant find component factory

Current behavior
I declared those dynamic components as entry components in the module where I also want to render them. With JIT it works fine.
Following structure has the part of my app I want to render them: app -> home (lazy) -> contracts (lazy) -> search.
So I added those components to the module I use for the search component/route. When I'm compiling with AOT, everytime I visit the search route, the app tells me there is no component factory. Of course I searched google and found some results:
I tried adding them to the ANALYZE_FOR_ENTRY_COMPONENTS provider, I tried to import a ModuleWithProviders with .forRoot() in my app.module and I also tried simply importing and declaring my dynamic and all of its dependant components in the root module (app.module). Everything resulting in the same error.
I declare my dynamic components as entry components like so:
#NgModule({
imports: [SharedComponentsModule, FinoSchemaFormsModule, TabGroupModule, FinoInputModule],
declarations: [EnergySearchSettingsComponent, DslSearchSettingsComponent, MobileSearchSettingsComponent, ComparisonDetailSectionComponent],
entryComponents: [EnergySearchSettingsComponent, DslSearchSettingsComponent, MobileSearchSettingsComponent],
exports: [EnergySearchSettingsComponent, DslSearchSettingsComponent, MobileSearchSettingsComponent, ComparisonDetailSectionComponent],
providers: [CategoryMappingProvider]
})
export class ComparisonComponentsModule { }
This module gets imported in the SearchModule, where also my SearchComponent is declared. In this component I want to render those components dynamically using the ComponentFactoryResolver I inject in the SearchComponent.
ngOnInit() {
this.searchSettingsComponent = this.comparisonService.getSearchComponent(); // returns either EnergySearchSettingsComponent, DslSearchSettingsComponent or MobileSearchSettingsComponent
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(searchSettingsComponent);
this.searchSettingsComponent = this.searchContainer.createComponent(componentFactory);
this.searchSettingsComponent.instance.comparisonSettings = comparisonSettings;
this.searchSettingsComponent.instance.onSave.subscribe(settings => this.saveSearchSettings(settings));
}
The SearchComponent is the routing component of the search route, which is a child route of my contract route, which gets lazy loaded. This again is a child route of my home route (also lazy loaded) and this belongs to the main route.
Environment
Angular version: 5.2.4
For Tooling issues:
- Node version: 8.11.3
- Platform: Mac
It must be pretty simple. Just create the SharedModule and put all reusable dynamic component in it, export those components from SharedModule and import this Module in all required. Lazy loaded Modules.
Since it is imported direct to the Module, it must be available while creating the Dynamic Component.
Have you tried updating angular to latest 6.1.10? With version 5 I had issues with lazy loaded modules.
I had a similar task, and it worked fine under 6.1.4.
I've created a working example for you under 7.0.1
I've created both cases
Dynamic component is declared in the module which will create the dynamic component
Dynamic component is declared in a shared module and imported in the lazy-loaded module which will create dynamic components. You can create a shared module for every dynamic component, so you import only one component in a lazy loaded module
I don't feel as though there is enough information in your question to give you the exact answer to the problem you are facing.
I was able to create a solution with, what I feel is a similar setup to yours that you could use to solve your problem or to ask a more pointed question.
TLDR: Full GitHub repo here
I created an app structure as follows:
app/
app.module
app.component
/dynamic-provider --contains component that is dynamically loading other components
--module is lazy loaded by dynamic-one module
dynamic-loader.module
slot.component
/dynamic-one --contains lazy loaded module
--module is lazy loaded by app module
dynamic-one.module
/dynamic-loader --contains a component to be dynamically loaded
dynamic-provider.module
one.component
provider.service
app.module looks as follows
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
RouterModule.forRoot([
{ path: 'dynamic-loader', loadChildren: './dynamic-one/dynamic-one.module#DynamicOneModule' },
{ path: '', component: AppComponent }
])
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
dynamic-one.module looks as follows
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
#NgModule({
imports: [
RouterModule.forChild([
{ path: '', loadChildren: '../dynamic-loader/dynamic-loader.module#DynamicLoaderModule' }
])
]
})
export class DynamicOneModule {
constructor() {
console.log('one');
}
}
dynamic-loader.module looks as follows
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
import { DynamicProviderModule } from '../dynamic-provider/dynamic-provider.module';
import { SlotComponent } from './slot.component';
#NgModule({
declarations: [ SlotComponent ],
imports: [
DynamicProviderModule,
RouterModule.forChild([
{ path: '', component: SlotComponent }
])
]
})
export class DynamicLoaderModule { }
dynamic-provider.module looks as follows
import { NgModule } from '#angular/core';
import { OneComponent } from './one.component';
import { ProviderService } from './provider.service';
#NgModule({
declarations: [ OneComponent ],
entryComponents: [ OneComponent ],
exports: [ OneComponent ],
providers: [ ProviderService ]
})
export class DynamicProviderModule { }
As you state, your dynamic creation of components is working when the module isn't loaded, so I haven't included that code here(though it is in the repo for completeness). As can be seen here though, the app module lazy loads the dynamic-one module which in turn lazy loads the dynamic-loader module. The dynamic-loader module dynamically creates components from the dynamic-provider module.
How this differs from your implementation is very hard to tell as you have provided only a small amount of information. I hope this helps you find the missing piece you are looking for though!
Creating shared modules allows you to organize and streamline your
code. You can put commonly used directives, pipes, and components into
one module and then import just that module wherever you need it in
other parts of your app.
By re-exporting CommonModule and FormsModule, any other module that imports this SharedModule, gets access to directives like NgIf and NgFor from CommonModule and can bind to component properties with [(ngModel)], a directive in the FormsModule.
EX:
import { CommonModule } from '#angular/common';
import { NgModule } from '#angular/core';
import { ReactiveFormsModule } from '#angular/forms';
import { SharedModule } from '../../shared/shared.module';
import { EntryModalComponent } from './entry-modal.component';
#NgModule({
imports: [
CommonModule,
SharedModule,
ReactiveFormsModule
],
declarations: [ EntryModalComponent ],
entryComponents: [ EntryModalComponent ],
exports: [ EntryModalComponent ]
})
export class EntryModalModule { }
Now you can use this EntryModalComponent for dynamic loading in some other component after importing the module where it's defined.
In the latest versions Angular has updated a lot of staff about lazy loaded modules. And with high probability this trouble is fixed now.

Inject nestjs service from another module

I've got a PlayersModule and an ItemsModule.
I want to use the ItemsService in the PlayersService.
When I add it by injection:
import { Injectable } from '#nestjs/common';
import { InjectModel } from 'nestjs-typegoose';
import { ModelType, Ref } from 'typegoose';
import { Player } from './player.model';
import { Item } from '../items/item.model';
import { ItemsService } from '../items/items.service';
#Injectable()
export class PlayersService {
constructor(
#InjectModel(Player) private readonly playerModel: ModelType<Player>,
private readonly itemsService: ItemsService){}
I get this nest error :
[Nest] 11592 - 2018-8-13 11:42:17 [ExceptionHandler] Nest can't
resolve dependencies of the PlayersService (+, ?). Please make sure
that the argument at index [1] is available in the current context.
Both modules are imported in the app.module.ts. Both services are working alone in their module.
You have to export the ItemsService in the module that provides it:
#Module({
controllers: [ItemsController],
providers: [ItemsService],
exports: [ItemsService]
^^^^^^^^^^^^^^^^^^^^^^^
})
export class ItemsModule {}
and then import the exporting module in the module that uses the service:
#Module({
controllers: [PlayersController],
providers: [PlayersService],
imports: [ItemsModule]
^^^^^^^^^^^^^^^^^^^^^^
})
export class PlayersModule {}
⚠️ Don't add the same provider to multiple modules. Export the provider, import the module. ⚠️
Let' say you want to use AuthService from AuthModule in my TaskModule's controller
for that, you need to export authService from AuthModule
#Module({
imports: [
....
],
providers: [AuthService],
controllers: [AuthController],
exports:[AuthService]
})
export class AuthModule {}
then in TaskModule, you need to import AuthModule (note: import AuthModule not the AuthService in TaskModule)
#Module({
imports:[
AuthModule
],
controllers: [TasksController],
providers: [TasksService]
})
export class TasksModule {}
Now you should be able to use DI in TaskController
#Controller('tasks')
export class TasksController {
constructor(private authService: AuthService) {}
...
}
The question is answered by Kim Kern. But I just want to remind people who read through this comment. Whenever you get this error, you should follow these steps that may help you easily figure out where the stuck is:
Make sure the Module which provides providers was imported.
Make sure the provider which you are using is exported.
For example, you have category module which contains category service, post module has post service and it has category service as a dependency:
#Module({
controllers: [CategoryController],
providers: [CategoryService],
exports: [CategoryService] // Remember to export
})
export class CategoryModule {}
And
#Module({
imports: [CategoryModule], // Make sure you imported the module you are using
controllers: [PostController],
providers: [PostService]
})
export class PostModule {}
Don't forget to use this annotation.
Nest uses this to detect singleton class.
In spring boot - Java, this one used to be called Bean. Read more:
#Injectable()
export class PostService {
constructor(private readonly categoryService: CategoryService // This will be auto injected by Nestjs Injector) {}
}
I solved my problem by removing #Inject() from the argument in my constructor that was passing the exported service.
I believe that you faced the same problem i had. My scenario was 2 sibling custom modules (user, auth) that needed to use each other's services. I used circular DI to solve it. please check this link
Let me know whether if it solved your issue, maybe I can advise you further.
Solved my problem by changing the way of importing the constant string (TOKEN) used in #Inject()) of my provider... be careful using index.ts whith export * from module.ts, nest won't resolve the dependecy
Based on the answer by Kim Kern nowadays we should add only injected service into our service without any decorators (#Inject() doesn't required). After that it will work right. That was my mistake and probably can help others.
Steps 1. Export the file that you want
Step 2. Import the whole module.
I initially made a mistake of adding the file as provider and also adding the module which was throwing error.

Issue setting up dependencies for Angular testbed with ng bootstrap elements despite importing NgbModule.forRoot()

I'm having trouble setting up the dependencies for a component that includes an ng bootstrap modal. The following code is from a test project that isolates the issue. The component works and runs with no errors when the website is served but there seems to be a dependency issue with the tests. I'm using the NgbModal service to open and close the modal within the component. Here's the setup of the component:
#Component({
selector: 'app-main-component',
templateUrl: './main.component.html',
styleUrls: ['./main.component.css'],
providers: [ NgbModal ]
})
export class MainComponent implements OnInit {
constructor(private modalService: NgbModal) { }
and here's where the dependencies are set up in the app.module.ts:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { MainComponent } from './main/main.component';
import { NgbModule } from '#ng-bootstrap/ng-bootstrap';
#NgModule({
declarations: [
AppComponent,
MainComponent
],
imports: [
BrowserModule,
NgbModule.forRoot()
],
bootstrap: [AppComponent]
})
and the dependencies for the testbed are set up in the main.component.ts file here:
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MainComponent ],
imports: [ NgbModule.forRoot(), BrowserModule ],
providers:[ NgbModal ]
})
.compileComponents();
component = TestBed.get(MainComponent);
modalService = TestBed.get(NgbModal);
}));
When I try to run the tests it's giving me this error
Failed: StaticInjectorError(DynamicTestModule)[NgbModal -> NgbModalStack]:
StaticInjectorError(Platform: core)[NgbModal -> NgbModalStack]:
NullInjectorError: No provider for NgbModalStack!
which seems to imply there's a missing dependency. With errors like this in the main app it seems like it's usually caused by the NgbModule.forRoot() not getting imported but it's in the imports for the test.
Thank you for your time.
Turns out the issue wasn't in my main component spec file, it was an issue running the test for my app component spec file. Since the component was used in the main app component it needed to have the same imports in the app component spec file.

Normal website body as Angular 2 Componentwithout replacing them

I want to make my website modern with some cool features.
For this I used jQuery and self made things. But that's slow and everything I developed is easier in Angular.
So I started to implement the Angular 2 code into my normal website.
The things (app.component, main.ts, app.module) work. I have the angular functionality on my page.
That's the first try.
Now I found out that I can't use second and third components (this ones which are not in bootstrap array) not within the selector.
So the bootstrapped component is the root-element for everything I think.
The next step was to replace the whole body as a component.
For example with angular 1 it was easy: ng-controller="app" and finish.
I can do this with <body> and everything.
Now with Angular 2 I must define a template for the component. else I get this error Uncaught Error: No template specified for component AppComponent
So the questions are...
Is it possible to use the as selector for the app so that I can use components within the app without bootstrapping them?
Or is there a way to use the components flexible?
The main reason is:
I want to define components globally which must not exist on each page. So I can have a component which is called test-component which is only used on test.html and a about-component which is only used on about.html
You understand?
Currently the problem is that I get this error: app.js:116448EXCEPTION: Error in :0:0 caused by: The selector "my-app" did not match any elements and ORIGINAL EXCEPTION: The selector "my-app" did not match any elements
If I define them both it works. But if one component is missing then I get this error.
Current scripts:
main.ts
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
app.component.ts
import { Component } from '#angular/core';
import {Http} from "#angular/http";
#Component({
selector: 'my-app',
template: `<h1>Hello {{name}}</h1> <a (click)="test()">:)</a>`
})
export class AppComponent {
constructor (private http: Http) {}
name = 'Angular';
test() {
alert('Yay');
return this.http.get('/asd/aaa/test').subscribe((a) => {
console.log('A', a);
}, (b) => {
console.log('B', b);
});
}
}
app.module.ts
import {NgModule} from '#angular/core';
import {BrowserModule} from '#angular/platform-browser';
import {AppComponent} from './app.component';
import {JsonpModule, HttpModule} from "#angular/http";
import {FormsModule} from "#angular/forms";
import {TestComponent} from "./test.component";
#NgModule({
imports: [
BrowserModule,
FormsModule,
HttpModule,
JsonpModule
],
declarations: [
AppComponent,
TestComponent
],
bootstrap: [
AppComponent,
// TestComponent // this shouldnt be a bootstrap because else the component MUST exist on the page!
]
})
export class AppModule {
}
test.component.ts
import { Component } from '#angular/core';
import {Http} from "#angular/http";
#Component({
selector: 'test-app',
template: `<h1>Hello {{name}}</h1> <a (click)="test()">:)</a>`
})
export class TestComponent {
constructor (private http: Http) {}
name = 'Angular !!!!!!!!!!!!';
test() {
alert('yyyyy');
return this.http.get('/asd/aaa/test').subscribe((a) => {
console.log('A', a);
}, (b) => {
console.log('B', b);
});
}
}
As I said if I want to use the body as root element it replaces everything of the body. And this is not for my use case.
It's only a normal website. Multiple HTML (background = PHP) pages.
I could implement this platformBrowserDynamic().bootstrapModule(AppModule); on each page where I need something. Then I could write a module for each page. I think this could solve the problem, too. But it's bad... Having a lot of modules...

Categories

Resources