I have the following function:
export function toCamelCase(string): string {
//code omitted
}
Then I use it on my feature components by adding reference as:
import * as utility from '../shared/functions/helper-functions';
However, I use a shared module and I am wondering if it is possible to add this helper function reference only to shared module and export it so that I can use its functions without adding its reference (I already add shared.module reference). Any idea?
import * as utility from '../shared/functions/helper-functions';
#NgModule({
declarations: [
//...
],
imports: [
//...
],
exports: [
// I want to add helper function as a module
],
providers: [
//...
})
export class SharedModule { }
Just export class SharedModule and export * from '../shared/functions/helper-functions' as well.
If you really want to expose the helper functions in the Angular module, you could expose them as services (in the providers section) but that wouldn't really make sense.
Related
I create a Firebase provider like below(without using module file with exports and imports):
#Injectable()
export class FirebaseProvider {
public app: admin.app.App;
constructor() {
this.app = admin.initializeApp(config);
}
}
and add this provider to providers in AppModule:
providers: [AppService, FirestoreProvider, ClientService],
and in ClientModule:
providers: [CustomersService, FirestoreProvider],
so, now i want to use this provider in my ClientService, so I inject this provider via constructor like below:
constructor(
private readonly firestoreProvider: FirestoreProvider,
) {}
and now i have a problem, can somone tell me why NestJs inject me this provider more than one time and because of this firebase throw me this error:
The default Firebase app already exists. This means you called initializeApp() more than once without providing an app name as the second argument. In most cases you only need to call initializeApp() once. But if you do want to initialize multiple
apps, pass a second argument to initializeApp() to give each app a unique name.
I initialize this firebase only in this provider, so how to properly use this provider in services across the whole project?
thanks for any help!
I don't think you want to declare your FirestoreProvider in the provider:[] array of a module more than once. Try something like this:
#Module({
imports: [
FirestoreModule
],
})
export class AppModule{}
Now that you've imported the FirestoreModule, you can use it in any class that is in this AppModule. Example:
#Injectable()
export class FooService {
constructor(private firestore: FirestoreProvider) {}
}
The key here is to define your provider in its own module, then export it via the exports:[] array, and provide it via the providers:[] array of that module.
import { FirestoreProvider } from './FirestoreProvider'
#Module({
providers: [ FirestoreProvider ],
exports: [ FirestoreProvider ],
})
export class FirestoreModule{}
#Injectable()
export class FirestoreProvider {
public app: admin.app.App;
constructor() {
this.app = admin.initializeApp(config);
}
}
I'm struggling to figure out on how to provide services from DynamicModule to regular Modules. Pseudocode below:
app.module.ts
#Global()
#Module({
imports: [
DynamicModule.forRoot(config),
RegularModule,
],
providers: [],
exports: [],
})
export class AppModule {}
dynamic.module.ts
#Module({})
export class DynamicModule implements OnModuleInit, OnModuleDestroy {
constructor(private dynamicService: dynamicService) {}
static forRoot(config: Config): DynamicModule {
return {
module: DynamicModule,
imports: [],
providers: [
{
provide: CONFIG_TOKEN,
useValue: config,
},
DynamicService,
],
exports: [
DynamicService,
],
};
}
}
dynamic.service.ts
#Injectable()
export class DynamicService {
constructor(
#Inject(CONFIG_TOKEN) private readonly config: Config,
) {}
}
regular.module.ts
#Module({
imports: [],
providers: [RegularService, DynamicService],
exports: [RegularService],
})
export class RegularModule {}
regular.service.ts
#Injectable()
export class RegularService {
constructor(
private readonly dynamicService: DynamicService
) {}
}
Providing DynamicService to RegularModule requires to provide CONFIG_TOKEN in RegularModule as well, which seems odd and not practical in case more modules would depend on DynamicService and doesn't seem to be the correct way.
What concepts am I missing and what is correct approach to use services of a DynamicModule?
Would something as forFeature in DynamicModule method would be the right direction?
dynamic modules are modules that need some sort of context defined input, classic example is a database module that would need at least the host url and credentials, which would vary by app.
This means that when the forRoot(input) returns, you have a module just like any regular (non dynamic) module. As such, you can make use of the config value inside the dynamic module's service, export the service on the dynamic module, and then inject that service on other modules that import your dynamic module.
There is no need to also inject the config value on the service that injected the dynamicService.
If you need to have direct access to the config value inside of regularService, and that value is being shared across multiple services and modules, then you should take a look at the ConfigModule and treat that config value as env. If by some very specific reason it cant or should not be in env, then still you should create a separate module for providing this config values.
The only way I know of being able to use my directive is by exporting it in the module.
#NgModule({
imports: [
CommonModule
],
declarations: [BreadcrumbsComponent, IsRightDirective],
exports: [BreadcrumbsComponent, IsRightDirective]
})
export class BreadcrumbsModule { }
My BreadcrumbsModule is imported by my AppModule
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BreadcrumbsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Now when I use my breadcrumbs component, which I named the selector bulma-breadcrumbs, and add the attribute, is-right, it works as expected. However if I add it to another tag, like an h1, the directive also affects it.
I'm trying to get the directive to only apply on the BreadcrumbsComponent.
Before Angular 2 RC5, a hierarchy of directives/components was transparent, because components had directives property that defined components/directives that affected only this component and its children.
After the introduction of NgModule, this feature remained intact but became less evident. As explained in this answer, it's possible with proper hierarchy of modules.
Most times module declarations and exports are same, this allows to use module directives, components and pipes globally within the application.
If a unit isn't exported from a module, it's available only locally, to other units within same module.
This
#NgModule({
imports: [
CommonModule
],
declarations: [BreadcrumbsComponent, IsRightDirective],
exports: [BreadcrumbsComponent]
})
export class BreadcrumbsModule { }
will prevent is-right attribute directive from being compiled anywhere but this module declarations (i.e. BreadcrumbsComponent).
Alternatively, directive selector can be restricted to bulma-breadcrumbs[is-right]. The result will be same, but this won't prevent the directive from being used in other modules that have their local bulma-breadcrumbs component.
You can make the directive effective only if the element tagName is bulma-breadcrumbs:
export class IsRightDirective {
constructor(private elementRef: ElementRef) {
let element = elementRef.nativeElement as HTMLElement;
if (element.tagName.toLowerCase() === "bulma-breadcrumbs") {
element.style.border = "solid 4px red";
...
}
}
}
See this stackblitz for a working example of the code.
I am pretty new in Angular 2. I am studying how to create modules into an Angular app and I have the following doubt related a tutorial that I am following.
My doubt is related to the routing.
So in my example there is defined this AuthModule module:
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { SigninComponent } from './signin/signin.component';
import { SignupComponent } from './signup/signup.component';
import { AuthRoutingModule } from './auth-routing.module';
#NgModule({
// Components and directives used by the module:
declarations: [
SigninComponent,
SignupComponent
],
// Import modules used by this features module:
imports: [
FormsModule,
AuthRoutingModule
]
})
export class AuthModule {}
and I have the related rotues configuration class defined:
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { ShoppingListComponent } from './shopping-list/shopping-list.component';
const appRoutes: Routes = [
{ path: '', redirectTo: '/recipes', pathMatch: 'full' },
{ path: 'shopping-list', component: ShoppingListComponent }
];
#NgModule({
imports: [RouterModule.forRoot(appRoutes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
So I think that the export keyword means that the content related to this class can be exported and used somewhere else (in this case I think into the imports array of the AuthModule class).
Is it? Or am I missing something? What it the exact meaning of the export statment?
I am not understanding if it is something related to Angular or more generally to TypeScript (because here I found https://www.typescriptlang.org/docs/handbook/modules.html). So it seems to me that this module concept is not directly bounded to Angular 2 framework but is a TypeScript concept to subdivide our code in a smart way (then Angular 2 can use this kind of feature of the language).
Is it or am I missing something?
Angular imports/exports and TypeScript imports/exports are two different concepts.
TypeScript imports/exports work at language level to make it clear what
a used identifier references exactly. This is entirely unrelated to Angular.
So, if you use FormsModule there can't be any ambiguity, what FormsModule is meant. If there is more than one FormsModule in your code or any of your dependencies, then you need to make it clear with imports which one is meant. You can't import 2 FormsModule from different locations without disambiguation (for example using as foo in the import and then reference it using foo.FormsModule).
This way you can use code from arbitrary 3rd-party libraries and avoid name collisions.
Angular imports/exports are used to make the content of one module available to be used in another module.
Your:
imports: [
FormsModule,
AuthRoutingModule
]
Allows you to use the directives from FormsModule and AuthRoutingModule in AuthModule and registers the services provided by these modules in the AppModule scope or the closed lazy-loaded root scope.
If you reference any of Angulars directives or services in TypeScript code, you also need to add TypeScript imports. Above FormsModule and AuthRoutingModule need to be imported with TypeScript imports, to make the Angular imports: [...] work.
For example like
<form #f="ngForm">
<input type="text">
</form>
works only if FormsModule is listed in imports: [ ... ] of your current module.
There is no TypeScript import required, because there is no TypeScript code.
Yes you are right by using export keyword before your typescript class you can use that class somewhere else .. in your project
I have a service in sub-module that wraps some third-party module, instantiates and initializes its service to prepare for use within app.
#Injectable()
class SubmoduleInitializerService {
constructor (thirdPartyService: ThirdPartyService) {
thirdPartyService.initialize(...);
...
}
}
#NgModule({
imports: [ThirdPartyModule],
exports: [ThirdPartyModule],
providers: [
ThirdPartyService,
SubmoduleInitializerService
]
})
class AppSubmodule {}
ThirdPartyService isn't injected in app directly but is used by other ThirdPartyModule units, so as long as SubmoduleInitializerService is injected in the same injector as ThirdPartyService or parent injector, everything is fine:
export class AppComponent {
constructor(
/* DO NOT REMOVE! BAD THINGS HAPPEN! */
submoduleInitializerService: SubmoduleInitializerService
) {}
...
}
It was proven to be a lousy pattern because it is not obvious why SubmoduleInitializerService should stay injected in AppComponent if it's not used neither in class nor in template (was accidentally removed once already).
Basically AppSubmodule module needs an alternative to Angular 1.x angular.module(...).run(...) block.
What are the options here?
APP_INITIALIZER (undocumented) service plays the role of AngularJS config/run blocks reasonably well in Angular 2 (not counting the feature of asynchronous initialization).
For noop intialization block that just eagerly instantiates SubmoduleInitializerService it is:
#NgModule({
imports: [ThirdPartyModule],
exports: [ThirdPartyModule],
providers: [
ThirdPartyService,
SubmoduleInitializerService,
{
provide: APP_INITIALIZER,
useFactory: () => () => {},
deps: [SubmoduleInitializerService],
multi: true
}
]
})
class AppSubmodule {}
Since APP_INITIALIZER is multi-provider, it allows to have several initialization functions per application that follow the order in which the modules are being loaded.
For synchronous initialization the shorter (and probably more appropriate) alternative is to inject the service into module's constructor:
#NgModule({
imports: [ThirdPartyModule],
exports: [ThirdPartyModule],
providers: [
ThirdPartyService,
SubmoduleInitializerService
]
})
class AppSubmodule {
constructor(sis: SubmoduleInitializerService) {}
}
As explained in this answer, APP_INITIALIZER shares some traits with config block, too, because it is used to configure services prior to component initialization and is susceptible to race conditions (for example, since APP_INITIALIZER is used to configure Router, injecting it into another APP_INITIALIZER will result in circular dependency).