angular 5 Error: Can't resolve all parameters for Service - angular5

I could use a little help.
Context I am making a angular 5 module for an authentication service.
How do I pass a POJO into a class as parameters?
See my answer below.
I need to use HttpClient inside this auth service
I am getting this error:
Error: Can't resolve all parameters for AuthService: ([object Object], ?).
[object Object] is angular 5 HttpClient
Can some one please explain why I am getting this error and how to resolve it?
#NgModule()
export class AuthtModule {
static forRoot(params?: iParams) {
return {
ngModule: AuthModule,
provides: [
HttpClient,
{
provide: AuthService,
useFactory: setupAuthService,
deps: [ HttpClient, params ]
}
],
imports: [ HttpClientModule ],
exports: [ AuthService ]
}
}
}
Thanks in advance.
Cheers

I figured out how to do this, as it turns out the problem was with the second parameter (hence the question mark) not the first. the reason this error occurs is because in order for parameters to be passed into a class they must first be turned into a injectable.
Here is how you do it.
First create a class model with the params
foo-params.model.ts
export class FooParams {
public foo1: string;
public foo2: number;
}
Then In the Module class attributes set the class FooParams to use the values that are a POJO
app.module.ts
import { HttpClientModule, HttpClient } from '#angular/common/http';
import { FooParams } from './foo-params';
#NgModule({
imports : [ HttpClientModule ],
providers: [{
HttpClient
{ provider: FooParams, useValue: params },
{
provider: BarService,
useFactory: setupBarService
deps: [ HttpClient, FooParams ]
}
}]
})
export class AppModule {}
And this is what the class that consumes the pojo would look like.
bar.service.ts
import { HttpClient } from '#angular/common/http';
import { FooParams } from './foo.service.ts';
expecto function setupBarService(http: HttpClient, params: FooParams) {
return new BarService(http, params);
}
#Injectable()
export class BarService {
constructor(http: HttpClient, params: FooParams) {}
//DO STUFF
}

Try by importing import 'core-js/es7/reflect'; in polyfills.ts

Related

How to install Express middleware (express-openapi-validator) in NestJS?

I am writing a NestJS application. Now I want to install the Express middleware express-openapi-validator.
However, I can't get it to work. There is a description for how to install the express-openapi-validator in express, but it always results in errors.
For example
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(middleware({apiSpec "./bff-api.yaml"}))
.forRoutes(OrganizationController)
}
}
results in
error TS2345: Argument of type 'OpenApiRequestHandler[]' is not assignable to parameter of type 'Function | Type<any>'.
Type 'OpenApiRequestHandler[]' is missing the following properties from type 'Type<any>': apply, call, bind, prototype, and 4 more.
How can I install this middleware in NestJS?
I added a NestJS example to express-openapi-validator (static link for posterity).
The AppModule looks basically identical, although you don't need to iterate over the middlewares:
#Module({
imports: [PingModule],
providers: [{ provide: APP_FILTER, useClass: OpenApiExceptionFilter }],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(
...OpenApiValidator.middleware({
apiSpec: join(__dirname, './api.yaml'),
}),
)
.forRoutes('*');
}
}
I also added an exception filter to convert the error from express-openapi-validator to a proper response; otherwise I would always get a 500 error. You could also use this approach to convert the error into a custom error format.
import { ArgumentsHost, Catch, ExceptionFilter } from '#nestjs/common';
import { Response } from 'express';
import { error } from 'express-openapi-validator';
#Catch(...Object.values(error))
export class OpenApiExceptionFilter implements ExceptionFilter {
catch(error: ValidationError, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
response.status(error.status).json(error);
}
}
interface ValidationError {
status: number;
message: string;
errors: Array<{
path: string;
message: string;
error_code?: string;
}>;
path?: string;
name: string;
}
I have now got it working:
configure(consumer: MiddlewareConsumer) {
middleware({
apiSpec: `${__dirname}/../api-doc/bff-api.yaml`
}).forEach(value => consumer.apply(value).forRoutes(OrganizationController))
}

NestJs version for modules

I would like to add version for my modules, but i don't know how can I do this. I tried to create a common module.ts but the same name of services killed each us. I tried different module.ts for the versions, it was better but the services with same names didn't work.
This is my last structure:
test-module
1.0
controllers
test.controller.ts
services
test.service.ts
test.module.ts
1.1
controllers
test.controller.ts
services
test.service.ts
test.module.ts
This is my test service(s) for the versions:
import * as _ from 'lodash';
import { Injectable } from '#nestjs/common';
#Injectable()
export class TestService {
public test() {
return '1.0'; // and 1.1 in 1.1 directory
}
}
This is my module.ts:
import { Module, Logger } from '#nestjs/common';
import { TestModule as DorotTwo } from 'test-module/1.1/test.module';
import { TestModule as DorotOne } from 'test-module/1.0/test.module'
#Module({
controllers: [ProtobufController],
providers: [],
imports: [
DorotTwo,
DorotOne,
],
})
export class ProjectModule {
constructor() {
Logger.log('App initialized');
}
}
This is a simple test Controller in the project who want use the modules. A tried import TestService from 1.0 or 1.1 but the test function's response is always 1.0 because that is the last element in the import.
#Controller()
export class ProtobufController {
constructor(private readonly testService: TestService) {
console.log(this.testService.test()); // Always 1.0
}
.....
It is working if I use full different names for services for example (eg: UserAuthenticationService10, RegisterAuthenticationService10), but this is horrible and if i forget rename it in new version, it will overwrite.
Is exists an example where I can read how can I create this versioned module?
Would using custom providers be a satisfying solution for you?
Example:
// 1.0
#Module({
providers: [
{ provide: 'TestService_1.0', useClass: TestService }
]
})
export class TestModule {}
// 1.1
#Module({
providers: [
{ provide: 'TestService_1.1', useClass: TestService }
]
})
export class TestModule {}
// Then
#Controller()
export class ProtobufController {
constructor(
#Inject('TestService_1.0') private readonly testService_10,
#Inject('TestService_1.1') private readonly testService_11
) {
console.log(this.testService_10.test());
console.log(this.testService_11.test());
}
}
I obviously haven't tested this and you should adapt it to your usecase. I suggest you to have a look at https://docs.nestjs.com/fundamentals/custom-providers.

Set value in service from AuthGuard before service is initiated with Angular2 and Firebase

I'm trying to get the user ID from the currently logged in user to customize the data loaded from my DataService.
My goal is that:
The AuthGuard should be called before the InboxComponent is loaded
This AuthGuard should set the user variable in the AuthService
I should then be able to use the authService.user in the DataService
However, the console.log(this.authService.user) yields undefined although the console.log(authState) in the AuthGuard correctly logs the user information.
Any clues on what could be wrong?
Authentication Service
export class AuthService {
public user: any;
constructor(private af: AngularFire, public auth$: FirebaseAuth) {
console.log("Auth service state:", this.authState);
}
AuthGuard
#Injectable()
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(): Observable<boolean> {
return this.authService.auth$
.take(1)
.map(authState => {
console.log(authState)
this.authService.setUser(authState);
return !!authState })
.do(authenticated => {
if (!authenticated) {
this.router.navigate(['/error']);
}
});
}
}
Dataservice
export class DataService {
private userPath: string;
constructor(private af: AngularFire, private authService: AuthService) {
console.log(this.authService.user);
}
Router
const routes: Routes = [
{ path: 'inbox', component: InboxComponent, canActivate: [AuthGuard] }
App Module
#NgModule({
declarations: [
InboxComponent
],
imports: [
EmailsModule
],
providers: [
AuthService,
AuthGuard
],
bootstrap: [AppComponent]
})
export class AppModule { }
I finally resolved this. I had a call to my DataService in my app.component.ts file to get some data in my navigation. This is loaded outside the router-module and thus called before the AuthService is called. This in turn caused the DataService before the AuthGuard was called.

ORIGINAL EXCEPTION: No provider for Auth! : Ionic Cloud Services

I set up Ionic Cloud Service and went through the initial process of authorizing a user.
import {Component} from '#angular/core';
import {NavController} from 'ionic-angular';
import {Auth, User, UserDetails, IDetailedError} from '#ionic/cloud-angular';
#Component({
templateUrl: 'build/pages/signup/signup.html'
})
export class SignupPage {
constructor(public auth: Auth, public user: User){
let details: UserDetails = {'email': 'hi#ionic.io', 'password': 'puppies123'};
this.auth.signup(details).then(() => {
// `this.user` is now registered
}, (err: IDetailedError<string[]>) => {
for (let e of err.details) {
if (e === 'conflict_email') {
alert('Email already exists.');
} else {
// handle other errors
}
}
});
}
}
For some reason I am getting this error:ORIGINAL EXCEPTION: No provider for Auth!
ORIGINAL STACKTRACE:
Error: DI Exception
Everything is setup to a tee like the ionic cloud docs suggest : https://docs.ionic.io/services/auth/#setup
I've looked everywhere for this answer
In the setup instructions it talks about how to add the ionic cloud NgModule to your module's imports:
https://docs.ionic.io/setup.html
import { CloudSettings, CloudModule } from '#ionic/cloud-angular';
const cloudSettings: CloudSettings = {
'core': {
'app_id': 'APP_ID'
}
};
#NgModule({
declarations: [ ... ],
imports: [
IonicModule.forRoot(MyApp),
CloudModule.forRoot(cloudSettings)
],
bootstrap: [IonicApp],
entryComponents: [ ... ],
providers: [ ... ]
})
export class AppModule {}
I had missed these steps. Making this change fixed the problem.
Try this
#Component({
templateUrl: 'build/pages/signup/signup.html',
providers: [Auth]
})
Not sure if it works because the ionic docs don't say anything about this, but it seems logical looking at your Error
Passing Auth in providers, starts to show that error in console:
Cannot read property 'config' of undefined

"No provider for AuthGuard!" using CanActivate in Angular 2

EDIT : Obviously this is outdated, now you provide your guard at the providers array in an NgModule. Watch other answers or official documentation for more information.
bootstrapping on a component is outdated
provideRouter() is outdated as well
I'm trying to setup Authentication in my project, using a login and AuthGuard from the Angular2 guide : https://angular.io/docs/ts/latest/guide/router.html
I'm using the release : "#angular/router": "3.0.0-beta.1".
I'll try to explain as much as possible, feel free to tell me if you need more details.
I have my main.ts file which boostraps the app with the following code :
bootstrap(MasterComponent, [
APP_ROUTER_PROVIDERS,
MenuService
])
.catch(err => console.error(err));
I load the MasterComponent, which loads a Header containing buttons that allow me to navigate through my app and it also contains my main for now.
I'm following the guide to make my app work the same way, with the following app.routes.ts :
export const routes: RouterConfig = [
...LoginRoutes,
...MasterRoutes
];
export const APP_ROUTER_PROVIDERS = [
provideRouter(routes),
AUTH_PROVIDERS
];
And the login.routes.ts from the guide, which defines my AuthGuard :
export const LoginRoutes = [
{ path: 'login', component: LoginComponent }
];
export const AUTH_PROVIDERS = [AuthGuard, AuthService];
my Master component has its own route definition, which also contains the guard I'm trying to setup. master.routes.ts :
export const MasterRoutes : RouterConfig = [
{ path: '', redirectTo: '/accueil', pathMatch: 'full' },
{
path: 'accueil',
component: AccueilComponent
},
{ path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] },
];
And I'm using the same files as the guide, which are auth.guard.ts, auth.service.ts, login.component.ts and login.routes.ts.
In my header.component.ts file, when I try to access any routes, it's working just fine, but when I try to access the guarded path (/dashboard), I get the No provider for AuthGuard! error.
I saw the recent post with the same issue as mine (NoProviderError using CanActivate in Angular 2), but to me the guard is bootstraped correctly up to the main.ts file, so my router should know which routes should be provided with the AuthGuard right ?
Any help or advice would be greatly appreciated.
Thanks !
I had this same issue after going through the Route Guards section of Routing and Authorization tutorial on the Angular website https://angular.io/docs/ts/latest/guide/router.html, it is section 5.
I am adding AuthGuard to one of my main routes and not to child routes like the tutorial shows.
I fixed it by added AuthGuard to my list of providers in my app.module.ts file, so that file now looks like this:
import { AppComponent } from './app.component';
import {AppRoutingModule} from './app-routing.module';
import {AuthGuard} from './auth-gaurd.service';
import { AnotherPageComponent } from './another-page/another-page.component';
import { LoginPageComponent } from './login-page/login-page.component';
#NgModule({
imports: [
BrowserModule,
FormsModule,
JsonpModule,
AppRoutingModule,
HttpModule
],
declarations: [
AppComponent,
LoginPageComponent,
AnotherPageComponent
],
providers: [AuthGuard],
bootstrap: [AppComponent]
})
export class AppModule { }
I have gone back through the tutorial and in their app.module.ts file, they do not add AuthGuard to the providers, not sure why.
Try to add
#Injectable({
providedIn: 'root'
})
no need to add to module provider.
Also, don't fall into the trap of using a literal for the guard class inside your routing configuration, just because some blog articles do:
{ path: 'whatever', component: WhatEverComponent, canActivate: ['WhatEverGuard'] }
is not going to work (No provider for...), instead, use the class directly:
{ path: 'whatever', component: WhatEverComponent, canActivate: [WhatEverGuard] }
Another hint, when lazy loading components, the guard is applied in the routing configuration of the parent component, not in the routing configuration of the lazy loaded component.
For those who still have this error - don't forget to include your AuthGuard service or class to main bootstrap function.
And don't forget to import this service before bootstrap runs.
import { bootstrap } from '#angular/platform-browser-dynamic';
import { AppComponent } from './app.component';
import { AuthGuard } from './shared/auth.service';
bootstrap(AppComponent, [
appRouterProviders,
AuthGuard
]);
Angular 2 team did not mention this in main router docs, and it took couple of hours for me to figure it out.
The answer is further down in the tutorial. See the file listings in the "Add the LoginComponent" topic under the "Component-less route:..." section in "Milestone 5: Route Guards". It shows AuthGuard and AuthService being imported and added to the providers array in login-routing.module.ts, and then that module being imported into app.module.ts.
login-routing.module.ts
...
import { AuthGuard } from './auth-guard.service';
import { AuthService } from './auth.service';
...
#NgModule({
...
providers: [
AuthGuard,
AuthService
]
})
export class LoginRoutingModule {}
app.module.ts
import { LoginRoutingModule } from './login-routing.module';
#NgModule({
imports: [
...
LoginRoutingModule,
...
],
...
providers: [
DialogService
],
...
Actually, it was only a typo in an import...
I was typing
import { AuthGuard } from './../Authentification/auth.guard';
instead of
import { AuthGuard } from './../authentification/auth.guard';
making it not working but at the same time not displaying me any error...
(sadface)
I encountered this issue when I was following a tutorial. I tried most of the answer here but not getting any success. Then I tried the silly way like putting the AuthGuard before the other services in the provider and it works.
// app.module.ts
..
providers: [
AuthGuard,
UserService,
ProjectService
]
Since you got the solution as it was due to syntax issue. I just wanted to share this info.
we need to provide the AuthGaudSerivce as provider in only that module that correspond to respective route. No need to provide in main module or root module as main module will automatically load all the given sub module.This helps in keeping the code modular and encapsulated.
for example, suppose we have below scenario
1. we have module m1
2. we have route m1r in module m1
3. route m1r has 2 route r1 and r2
4. we want to protect r1 using authGaurd
5. finally we have main module that is dependent on sub module m1
Below is just prototype, not the actual code for understanding purpose
//m1.ts
import {AuthGaurd} from './auth.gaurd.service'
import {m1r} from './m1r'
#NgModule(
imports: [m1r],
providers: [AuthGaurd]
)
export class m1{
}
//m1r.ts
import {AuthGaurd} from './auth.gaurd.service'
const authRoute = [
{path: '/r1', component: 'authComponent', canActivate: [AuthGaurd]},
{path: '/r2', component: 'other'}
]
export authRoute
//main.module.ts
import {m1} from ''
import {mainComponent} from ''
#NgModule({
imports: [m1],
bootstrap: [mainComponent]
})
export class MainModule{}
import { Injectable } from '#angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '#angular/router';
#Injectable()
export class AuthGuard implements CanActivate {
constructor(private router: Router) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (localStorage.getItem('currentUser')) {
// logged in so return true
return true;
}
// not logged in so redirect to login page with the return url
this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }});
return false;
}
}
Importing both HttpModule and HttpClientModule helped me.
import { HttpClientModule } from '#angular/common/http';
import { HttpModule } from '#angular/http';
you can try import AuthGuard in provider of that module and then import it in the routing component-routing.module.ts file also
#NgModule({
providers: [
AuthGuard
],})
This happened to me when I had setup my Routes incorrectly:
WRONG
const routes: Routes =
[
{
path: 'my-path',
component: MyComponent,
resolve: { myList: MyListResolver, canActivate: [ AuthenticationGuard ] }
},
];
Note that in this case canActivate was accidentally made a part of the resolve object.
CORRECT
const routes: Routes =
[
{
path: 'my-path',
component: MyComponent,
resolve: { myList: MyListResolver },
canActivate: [ AuthenticationGuard ]
},
];