"Error: No provider for TranslateStore!" while UI Unit testing translation service in Angular 4.
After I run ng test command I get the test cases failed error along with the above error message.
Try this:
import {TranslateFakeLoader,TranslateLoader,TranslateModule,TranslateService } from '#ngx-translate/core';
TestBed.configureTestingModule({
imports: [
...
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateFakeLoader
}
})
],
...
providers: [
TranslateService
]
Importing & adding TranslateStore to the providers in my lazy loaded module resolved issue for me.
import { TranslateModule,TranslateService,TranslateStore } from '#ngx-translate/core';
export function createTranslateLoader(http: HttpClient) {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}
#NgModule({
declarations: [...],
imports: [
TranslateModule.forChild(
{
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [HttpClient]
}
})],
providers:[TranslateStore ]
})
Check the issue link below for more information
https://github.com/ngx-translate/core/issues/883#issuecomment-502037966
Related
I am working on an app in Angular 14 that requires authentication/authorization, reason for witch I use Keycloak Angular
.
As per the instructions, I have first installed Keycloak Angular with:
npm install keycloak-angular keycloak-js
Then in fe\src\app\app.module.ts:
import { APP_INITIALIZER, NgModule } from '#angular/core';
import { KeycloakAngularModule, KeycloakService } from 'keycloak-angular';
import { BrowserModule } from '#angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { MaterialModule } from './shared/material.module';
import { FlexLayoutModule } from '#angular/flex-layout';
// Components
import { ErrorsComponent } from './shared/error.component';
import { AppComponent } from './app.component';
function initializeKeycloak(keycloak: KeycloakService) {
return () =>
keycloak.init({
config: {
url: 'http://localhost:8080/auth',
realm: 'demo',
clientId: 'my-app'
},
initOptions: {
onLoad: 'check-sso',
silentCheckSsoRedirectUri:
window.location.origin + '/assets/silent-check-sso.html'
}
});
}
#NgModule({
declarations: [
ErrorsComponent,
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
MaterialModule,
FlexLayoutModule,
KeycloakAngularModule
],
exports: [],
providers: [
{
provide: APP_INITIALIZER,
useFactory: initializeKeycloak,
multi: true,
deps: [KeycloakService]
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
I have also added silent-check-sso.html to the src\assets\ directory.
The problem
At http://localhost:4200/, I only see a blank page and the browser throws the error:
Refused to display 'http://localhost:8080/' in a frame because it set 'X-Frame-Options' to 'deny'.
Questions
What is causing this error?
What is the easiest and most reliable way to fix it?
This is due that Keycloak will prevent a website from including any login page within an iframe. This is to prevent clickjacking attacks.
To enable this just fallow this guide from keyclock documentation: https://www.keycloak.org/docs/15.0/server_admin/, just check after "Authorizing Iframes"
And also check if flags: checkLoginIframe is set to false.
I am developing an Angular library where there is an authentication module that provides an HttpInterceptor. The main idea is to have this interceptor working automatically in any app that imports this authentication module without having to do any extra setup at it.
What I have so far is the following:
AuthenticationModule
#NgModule({
imports: [ConcreteAuthModule],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: BearerInterceptor,
multi: true
}
]
})
export class AuthenticationModule {
static forRoot(config: AuthConfig): ModuleWithProviders {
return {
ngModule: AuthenticationModule,
providers: [
{
provide: AUTH_CONFIG,
useValue: config
}
]
};
}
}
ConcreteAuthModule
#NgModule({
imports: [ThirdPartyLibModule],
providers: [
{
provide: AuthenticationService,
useClass: ConcreteAuthService
}
]
})
export class ConcreteAuthModule { }
BearerInterceptor
#Injectable()
export class BearerInterceptor implements HttpInterceptor {
constructor(private authService: AuthenticationService) { }
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const headers: any = {};
if (this.authService.isUserAuthenticated()) {
headers.Authorization = `Bearer ${this.singleSignOnService.getUserToken()}`;
}
const authReq = req.clone({ setHeaders: headers });
return next.handle(authReq);
}
}
And from a test Angular app I am importing this module the following way at the AppModule:
#NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
HttpClientModule,
AuthenticationModule.forRoot({ /* config stuff */ })
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
I checked how some third party libraries did this, also came across a couple of Stack Overflow questions that discussed about this and they all suggested having an Angular module created (I already have it: AuthenticationModule), then provide the http-interceptor on it (already have it too) and finally importing this module from an Angular app (also did this).
But still, none of the http requests in my app are being intercepted.
Tried importing the BearerInterceptor directly from my test app and providing it on the AppModule like this:
import { BearerInterceptor } from 'my-lib':
#NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
HttpClientModule,
AuthenticationModule.forRoot({ /* config stuff */ })
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: BearerInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule {}
And that works! But this workaround is not what I am looking for...
You're very close to a working solution.
The key is to look at how the module is being imported by the AppModule.
imports: [
BrowserModule,
HttpClientModule,
AuthenticationModule.forRoot({ /* config stuff */ })
],
That is how the AuthenticationModule is imported by the AppModule, but that NgModule does not provide the HTTP_INTERCEPTORS.
You've provided the token in the #NgModule() decorator, but that module is not being used by your application. It's the module defined by the forRoot() function.
Move the declaration of the HTTP_INTERCEPTORS to the forRoot() function.
Try this instead:
#NgModule({
imports: [ConcreteAuthModule]
})
export class AuthenticationModule {
static forRoot(config: AuthConfig): ModuleWithProviders {
return {
ngModule: AuthenticationModule,
providers: [
{
provide: AUTH_CONFIG,
useValue: config
}, {
provide: HTTP_INTERCEPTORS,
useClass: BearerInterceptor,
multi: true
}
]
};
}
}
The problem was because I was installing the library locally for testing purposes like the following:
$ npm i --save my-lib_path/dist/my-lib
After I published it and installed it from the npm registry it worked fine:
$ npm i --save my-lib
I use i18n on my own component library, but it's not working
in my module
// AoT requires an exported function for factories
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}
#NgModule({
declarations: [myLibraryModuleComponent],
imports: [
CommonModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
})
],
exports: [myLibraryModuleComponent, TranslateModule]
})
export class myLibraryModule { }
I got
http://localhost:4200/assets/i18n/en.json
not found. It's not the good path
Are you using aot?
if yes, as per the documentation, you must use an exported function instead of an inline function
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [HttpClient]
}
})
Notice the createTranslateLoader between the parenthesis.
if no, try this:
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http);
}
I created Angular 5 project and create one factory which should provide metadata from service before application start.
The problem is that I get error:
RangeError: Maximum call stack size exceeded
at resolveNgModuleDep (core.js:10559)
at _callFactory (core.js:10649)
at _createProviderInstance$1 (core.js:10599)
at resolveNgModuleDep (core.js:10581)
at _createClass (core.js:10622)
at _createProviderInstance$1 (core.js:10596)
at resolveNgModuleDep (core.js:10581)
at NgModuleRef_.get (core.js:11806)
at new MetadataService (metadata.service.ts:23)
at _createClass (core.js:10622)
App module:
#NgModule({
declarations: [
AppComponent,
...
],
imports: [
BrowserModule,
HttpClientModule,
AppRoutingModule,
FormsModule,
FlexLayoutModule,
I18NextModule.forRoot()
],
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
MetadataService,
{ provide: APP_INITIALIZER, useFactory: MetadataProviderFactory, deps: [MetadataService], multi: true },
{ provide: APP_INITIALIZER, useFactory: I18NextProviderFactory, deps: [I18NEXT_SERVICE], multi: true }
],
bootstrap: [AppComponent]
})
export class AppModule { }
Metadata service:
import { Injectable, Injector } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class MetadataService {
private http: HttpClient;
constructor(private injector: Injector) {
this.http = injector.get(HttpClient); // this row makes a problem
}
This row makes a problem.
this.http = injector.get(HttpClient);
I put this line avoid circular reference and I get "Maximum call stack size exceeded".
Where I am wrong ?
You can temporarily get over this by delaying your http call that you make on service init, with a simple setTimeOut (don't need any seconds). I've gone through a few open Angular threads and the main issue has to do with HttpInterceptor and circular depedenecy with the HttpClient.
I currently have a module setup like below (exerpt);
AppModule
RoutingModule
AuthRouteGuard
AuthModule
LoginFormComponent
AuthService
I have defined my AuthService (responsible for handling user authentication and provides a method for determining whether the current user is authenticated) as a provider in my AuthModule;
// auth.module.ts - uses https://github.com/auth0/angular2-jwt
export function authHttpServiceFactory(http: Http, options: RequestOptions) {
return new AuthHttp(new AuthConfig({
tokenName: jwtLocalStorageKey
}), http, options);
}
export let authHttpServiceProvider = {
provide: AuthHttp,
useFactory: authHttpServiceFactory,
deps: [Http, RequestOptions]
};
#NgModule({
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule
],
exports: [AuthComponent],
declarations: [AuthComponent, LoginComponent, RegisterComponent],
providers: [
AuthService,
authHttpServiceProvider
]
})
export class AuthModule { }
I can use this service with no problem within its sibling LoginFormComponent. When I attempt to use the AuthService within the AuthRouteGuard class in the RoutingModule however I get the following error;
Error: Invalid provider for the NgModule 'AuthModule' - only instances of Provider and Type are allowed, got: [?undefined?, ...]
I have the AuthModule imported within the RoutingModule. The error above occurs as soon as the AuthService is defined as a dependency for the AuthRouteGuard;
export class AuthRouteGuard implements CanActivate {
constructor(
private router: Router,
private authService: AuthService // Removing this injection removes the error
) {}
canActivate() {
// #todo: if not authenticated
this.router.navigate(['/login']);
return true;
}
}
What am I missing here, and why would injecting the service in the constructor cause an invalid provider error that does not occur when that injection is removed?
Edit - Same error occurs if the authHttpServiceProvider provider is removed altogether, so the AuthModule module looks like;
#NgModule({
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule
],
exports: [AuthComponent],
declarations: [AuthComponent, LoginComponent, RegisterComponent],
providers: [
AuthService
]
})
export class AuthModule { }
Add authHttpServiceProvider to imports of the module. It's exported to global and not available to module. So you can't provide the service because you have unknown provider to the module.
#NgModule({
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule
],
exports: [AuthComponent],
declarations: [AuthComponent, LoginComponent, RegisterComponent],
providers: [
AuthService
]
})
export class AuthModule {
The actual problem was within the AuthService itself.
AuthModule defined a constant;
export const jwtKey = 'jwt';
Which was being imported into the AuthService and used;
import { jwtKey } from '../auth.module';
For some reason if I remove this import everything works fine.