I'm working on migrating my Angular 10 application to SSR using Angular universal and I'm facing issues with ngx-translate while translating parameterised values.
I have a translation
Bei Kauf von {quantity}
where this quantity is an attribute from our component and we normally translate it like
{{ 'LABEL' | translate: {quantity: 1} }} and we will see Bei Kauf von 1
But with SSR it's not at all translating. I see Bei Kauf von {quantity} on the page. I checked many forums and I don't see potential solutions. Any help would be much appreciated.
Here is my translate-server.loader.ts
import { join } from 'path';
import { Observable } from 'rxjs';
import { TranslateLoader } from '#ngx-translate/core';
import {
makeStateKey,
StateKey,
TransferState
} from '#angular/platform-browser';
import * as fs from 'fs';
export class TranslateServerLoader implements TranslateLoader {
constructor(
private transferState: TransferState,
private prefix: string = 'i18n',
private suffix: string = '.json'
) {}
public getTranslation(lang: string): Observable<any> {
return new Observable((observer) => {
const assets_folder = join(
process.cwd(),
'dist',
'my-app',
'browser',
'assets',
this.prefix
);
const jsonData = JSON.parse(
fs.readFileSync(`${assets_folder}/${lang}${this.suffix}`, 'utf8')
);
// Here we save the translations in the transfer-state
const key: StateKey<number> = makeStateKey<number>(
`transfer-translate-${lang}`
);
this.transferState.set(key, jsonData);
observer.next(jsonData);
observer.complete();
});
}
}
export function translateServerLoaderFactory(transferState: TransferState) {
return new TranslateServerLoader(transferState);
}
translate-browser.loader.ts
import { Observable } from 'rxjs';
import { TranslateLoader } from '#ngx-translate/core';
import {
makeStateKey,
StateKey,
TransferState
} from '#angular/platform-browser';
import { TranslateHttpLoader } from '#ngx-translate/http-loader';
import { HttpClient } from '#angular/common/http';
export class TranslateBrowserLoader implements TranslateLoader {
constructor(private http: HttpClient, private transferState: TransferState) {}
public getTranslation(lang: string): Observable<any> {
const key: StateKey<number> = makeStateKey<number>(
`transfer-translate-${lang}`
);
const data = this.transferState.get(key, null);
// First we are looking for the translations in transfer-state,
// if none found, http load as fallback
if (data) {
return new Observable((observer) => {
observer.next(data);
observer.complete();
});
} else {
return new TranslateHttpLoader(this.http).getTranslation(lang);
}
}
}
export function translateBrowserLoaderFactory(
httpClient: HttpClient,
transferState: TransferState
) {
return new TranslateBrowserLoader(httpClient, transferState);
}
app.server.module.ts
import { NgModule } from '#angular/core';
import { ServerModule, ServerTransferStateModule } from '#angular/platform-server';
import { FlexLayoutServerModule } from '#angular/flex-layout/server';
import { TranslateModule, TranslateLoader } from '#ngx-translate/core';
import { translateServerLoaderFactory } from './shared/loaders/translate-server.loader';
import { TransferState } from '#angular/platform-browser';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
import { EnvironmentService } from '~shared/services/environment.service';
#NgModule({
imports: [
AppModule,
ServerModule,
ServerTransferStateModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: translateServerLoaderFactory,
deps: [TransferState]
}
}),
FlexLayoutServerModule,
],
providers: [EnvironmentService],
bootstrap: [AppComponent],
})
export class AppServerModule {}
app.module.ts
imports: [
....,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: translateBrowserLoaderFactory,
deps: [HttpClient, TransferState]
}
}),
]
Note: It's working fine for all others which don't have any parameterised values in translations
It should be double curly brackets
Bei Kauf von {{quantity}}
wanna notice 2 more things, idk if it changed in last versions of Angular, but don't forget to register TransferState in app.module providers
providers: [
TransferState,
...
]
and for translate-server.loader.ts if you have some type errors for node.js use
/// <reference types="node" /> // add this line
import {join} from 'path';
at the top.
If it doesn't help, try to add
"types" : ["node", "express"],
to your tsconfig.json inside "compilerOptions"
It took me some time))
Related
I wanted to implement View Component Based On User Role In Angular 10 , to hide and show component. But I am block with the error above. Does anyone here has an idea about the issue? Help and idea would be much appreciated. Thanks.
#Role service code
import { Injectable } from "#angular/core";
import { HttpClient } from "#angular/common/http";
import { Observable } from "rxjs";
/**
* The Role Service service
*/
#Injectable()
export class RolesService {
private rolesAPi: string = "https://api.npoint.io/97c436983e2fbacffc7f";
constructor(private http: HttpClient) {}
/**
* gets the user role
*/
public roles(): Observable<{ roles: string[] }> {
return this.http.get<{ roles: string[] }>(this.rolesAPi);
}
}
component.html code
<p *appIfRoles='["Admin"]'>
ADMIN CONTENT IS VIEWED
</p>
if-roles.directive.ts directive code
import { Input, OnInit, Directive, ViewContainerRef, TemplateRef, OnDestroy } from "#angular/core";
import { Subject, Subscription } from "rxjs";
import { takeUntil } from "rxjs/operators";
import { RolesService } from "../../core/services/user-role.service"
#Directive({
selector: '[appIfRoles]'
})
export class IfRolesDirective implements OnInit, OnDestroy {
private subscription: Subscription[] = [];
// the role the user must have
#Input() public ifRoles: Array<string>;
/**
* #param {ViewContainerRef} viewContainerRef -- the location where we need to render the templateRef
* #param {TemplateRef<any>} templateRef -- the templateRef to be potentially rendered
* #param {RolesService} rolesService -- will give us access to the roles a user has
*/
constructor(
private viewContainerRef: ViewContainerRef,
private templateRef: TemplateRef<any>,
private rolesService: RolesService
) {}
public ngOnInit(): void {
this.subscription.push(
this.rolesService.roles().subscribe(res => {
if (!res.roles) {
// Remove element from DOM
this.viewContainerRef.clear();
}
// user Role are checked by a Roles mention in DOM
const idx = res.roles.findIndex((element) => this.ifRoles.indexOf(element) !== -1);
if (idx < 0) {
this.viewContainerRef.clear();
} else {
// appends the ref element to DOM
this.viewContainerRef.createEmbeddedView(this.templateRef);
}
})
);
}
/**
* on destroy cancels the API if its fetching.
*/
public ngOnDestroy(): void {
this.subscription.forEach((subscription: Subscription) => subscription.unsubscribe());
}
}
app.module.ts code
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { HttpClientModule, HTTP_INTERCEPTORS } from '#angular/common/http';
import { RouterModule } from '#angular/router';
import { LoginComponent } from './core/pages/login/login.component';
import { DashboardComponent } from './core/pages/dashboard/dashboard.component';
import { LayoutModule } from '#angular/cdk/layout';
import { SideNavComponent } from './core/components/side-nav/side-nav.component';
import { HeaderBarComponent } from './core/components/header-bar/header-bar.component';
import { UserprofileComponent } from './core/components/userprofile/userprofile.component';
import { UserInviteFormDialogComponent } from './core/components/user-invite-form-dialog/user-invite-form-dialog.component';
import { HeaderInterceptor } from './core/interceptors/header.interceptor';
import { RolesService } from './core/services/user-role.service';
import { SharedModule } from './shared/shared.module';
//import { AgmCoreModule } from '#agm/core';
import { ToastrModule } from 'ngx-toastr';
import { NgxMaskModule, IConfig } from 'ngx-mask';
import { IfRolesDirective } from './shared/directives/if-roles.directive';
// import { CoreModule } from './core/core.module';
const ngMaskConfig: Partial<IConfig> = {
validation: false,
};
#NgModule({
declarations: [
AppComponent,
IfRolesDirective,
LoginComponent,
DashboardComponent,
SideNavComponent,
HeaderBarComponent,
UserprofileComponent,
UserInviteFormDialogComponent,
,
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
LayoutModule,
RouterModule,
HttpClientModule,
// CoreModule,
ToastrModule.forRoot({
preventDuplicates: true,
enableHtml: true,
progressBar: true
}),
SharedModule,
NgxMaskModule.forRoot(ngMaskConfig),
],
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: HeaderInterceptor,
multi: true,},
RolesService,],
bootstrap: [AppComponent]
})
export class AppModule { }
You're almost there! Just missing the export in app.module.ts
#NgModule({
declarations: [
...
IfRolesDirective,
...],
imports: [...],
exports: [IfRolesDirective]
providers: [...],
})
Try the following code.
<p *ifRoles='["Admin"]'>
ADMIN CONTENT IS VIEWED
</p>
#Directive({
selector: '[ifRoles]'
})
export class IfRolesDirective implements OnInit, OnDestroy {
private subscription: Subscription[] = [];
// the role the user must have
#Input() public ifRoles: Array<string>;
....
....
}
I faced with next error and cannot understand how to resolve it.
Error: Can't resolve all parameters for LoginPage: ([object Object], [object Object], [object Object], ?).
I've checked almost every topic here and have tried multiple ways to resolve it but still can't beat it already second day.
Login.ts
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams,AlertController } from 'ionic-angular';
import { AuthProvider } from '../../providers/auth/auth';
import { TabsPage } from '../tabs/tabs';
/**
* Generated class for the LoginPage page.
*
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-login',
templateUrl: 'login.html',
})
export class LoginPage {
email:string = '';
password:string = '';
errorMsg:string;
constructor(
public navParams: NavParams,
public navCtrl: NavController,
public alertCtrl: AlertController
public authService: AuthProvider,
) {
}
ionViewDidLoad() {
console.log('ionViewDidLoad LoginPage');
}
errorFunc(message){
let alert = this.alertCtrl.create({
title: 'oops!',
subTitle: message,
buttons: ['OK']
});
alert.present();
}
myLogIn(){
if (this.email.trim() !=='' ) {
console.log(this.email.trim() + " " + this.password.trim() )
if (this.password.trim() === '') {
this.errorFunc('Please put your password')
}
else{
let credentials = {
email: this.email,
password: this.password
};
this.authService.login(credentials).then((result) => {
console.log(result);
this.navCtrl.setRoot(TabsPage);
}, (err) => {
console.log(err);
this. errorFunc('Wrong credentials ! try again')
console.log("credentials: "+JSON.stringify(credentials))
});
}
}
else{
this. errorFunc('Please put a vaild password ! for ex:(123456)')
}
}
myLogOut(){
this.authService.logout();
}
}
Auth.ts
import { Injectable } from '#angular/core';
import { Storage } from '#ionic/storage';
import { Http , Headers } from '#angular/http';
import { TabsPage } from '../../pages/tabs/tabs';
#Injectable()
export class AuthProvider {
rootPage:any = TabsPage;
public token:any;
constructor(public storage:Storage ,public http: Http) {
console.log('Hello AuthProvider Provider');
}
login(credentials){
return new Promise((resolve, reject) => {
let headers = new Headers();
headers.append('Access-Control-Allow-Origin' , '*');
headers.append('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT');
headers.append('Accept','application/json');
headers.append('Content-type','application/json');
headers.append('X-Requested-With','XMLHttpRequest');
this.http.post('http://127.0.0.1:8000/api/auth/login', JSON.stringify(credentials), {
headers: headers})
.subscribe(res => {
let data = res.json();
this.token = data.token;
localStorage.setItem('token',data.access_token);
resolve(data);
}, (err) => {
reject(err);
}); });
}
checkAuthentication(){
return new Promise((resolve, reject) => {
this.storage.get('token').then((value) => {
this.token = value;
resolve(this.token)
})
});
}
logout(){
localStorage.setItem('token','');
}
}
app.moodule.ts
import { NgModule, ErrorHandler } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { IonicStorageModule } from '#ionic/storage';
import { AboutPage } from '../pages/about/about';
import { ContactPage } from '../pages/contact/contact';
import { HomePage } from '../pages/home/home';
import { TabsPage } from '../pages/tabs/tabs';
import { LoginPage } from '../pages/login/login';
import { AddPage } from '../pages/add/add';
import { AuthProvider } from '../providers/auth/auth';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { HttpModule } from '#angular/http';
import { ComplaintProvider } from '../providers/complaint/complaint';
#NgModule({
declarations: [
MyApp,
AboutPage,
ContactPage,
HomePage,
TabsPage,
LoginPage,
AddPage
],
imports: [
BrowserModule,
IonicModule.forRoot(MyApp),
IonicStorageModule.forRoot(),
HttpModule
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
AboutPage,
ContactPage,
HomePage,
TabsPage,
LoginPage,
AddPage
],
providers: [
StatusBar,
SplashScreen,
AuthProvider,
ComplaintProvider,
{provide: ErrorHandler, useClass: IonicErrorHandler},
]
})
export class AppModule {}
You seem to be having a classic circular reference going around. You have the "TabsPage" imported in both Auth.ts & in your "LoginPage.ts".
A Classic Circular Reference.
Try removing the TabsPage from Auth.ts. In general, it is best if you have your components do very specific things so that you have a granular code and avoid such circular reference issues.
I am testing an angular 7 component that uses angular js components inside.
I am using jasmine and karma for testing.
I am getting
Angular Hybrid - **Error: Trying to get the AngularJS injector before it being set.** when I am running the ng test my-app-name.
app-module-ts -
import { BrowserModule } from '#angular/platform-browser';
import { NgModule, APP_INITIALIZER } from '#angular/core';
import { UpgradeModule, downgradeComponent } from '#angular/upgrade/static';
import { AppComponent } from './app.component';
import { BusyOverlayModule } from '../../../app-shared/src/lib/busy-overlay/busy-overlay.module';
import { L10nTranslationModule } from '../../../app-shared/src/lib/l10n-translation/l10n-translation.module';
import { LocalizationService } from '../../../app-shared/src/lib/l10n-translation/localization.service';
import { WatchlistModule } from './watchlist/watchlist.module';
import oprRtsmViewPickerModuleName
from '../../../../../../shared/shared-html/js/directives/oprRtsmViewPicker/oprRtsmViewPicker.module.js';
import oprTableFooterModuleName
from '../../../../../../shared/shared-html/js/directives/oprTableFooter/oprTableFooter.module.js';
import oprContextPanelModuleName
from '../../../../../../shared/shared-html/js/directives/oprContextPanel/oprContextPanel/oprContextPanel.module.js';
import { FilterFactory } from 'angular';
import oprPopupServiceModuleName from '../../../../../../shared/shared-html/js/services/oprPopup.service';
import ciContextDataServiceModuleName from '../../../../../../shared/shared-html/js/services/ciContextData.service';
import watchlistOptionsLauncherComponent from './watchlist/options-menu/watchlistOptionsLauncherNg1';
import oprLocalizationUtil from '../../../../../../shared/shared-html/js/utils/oprLocalizationUtil';
import appConstantsUtil from '../../../../../../shared/shared-html/js/utils/appConstantsUtil';
import { setAngularJSGlobal } from '#angular/upgrade/static';
import { oprContextPanelApiServiceProvider } from '../../../ng1-adapters/adapters/opr-conext-panel-api-provider';
import { ciContextDataServiceProvider } from '../../../ng1-adapters/adapters/opr-conext-data-api-provider';
import { Oprl10nPipe } from '../../../app-shared/src/lib/l10n-translation/oprl10n.pipe';
declare const angular: angular.IAngularStatic;
setAngularJSGlobal(angular);
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
UpgradeModule,
BusyOverlayModule,
L10nTranslationModule,
WatchlistModule
],
providers: [
{
provide: APP_INITIALIZER,
useFactory: onAppInit,
multi: true
},
oprContextPanelApiServiceProvider,
ciContextDataServiceProvider,
Oprl10nPipe
],
entryComponents: [
AppComponent
]
})
export class AppModule {
constructor(private upgrade: UpgradeModule, private localizationService: LocalizationService) { }
/**
* bootstrap hybrid AngularJS/Angular application with downgraded root Angular component
*/
ngDoBootstrap() {
const ng1L10nfilterFactory: angular.Injectable<FilterFactory> = function () {
return (key) => {
return oprLocalizationUtil.getLocalizedString(key);
};
};
const ng1RootModule = angular.module('ng1-root', [
oprPopupServiceModuleName,
oprRtsmViewPickerModuleName,
oprTableFooterModuleName,
oprContextPanelModuleName,
ciContextDataServiceModuleName
]).directive('oprRoot', downgradeComponent({component: AppComponent})).filter('oprL10n', ng1L10nfilterFactory)
.component('oprOptionsMenuLauncher', watchlistOptionsLauncherComponent);
this.localizationService.setOprLocalizeUtilObj(oprLocalizationUtil);
this.upgrade.bootstrap(document.body, [ng1RootModule.name], {strictDi: false});
}
}
export function onAppInit(): () => Promise<any> {
return (): Promise<any> => {
return new Promise((resolve, reject) => {
const appConstants = appConstantsUtil.appConstants;
/**
* For Testing, Replace this appConstants.locale.toLowerCase() code with en
*/
oprLocalizationUtil.init(appConstants.locale.toLowerCase(), appConstants.staticContext, [
'opr-watchlist',
'opr-common'
], function () {
resolve(true);
});
});
};
}
app.component.ts -
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'opr-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
showBusyOverlay:boolean = true;
ngOnInit() {
this.showBusyOverlay = false;
}
}
app.component.spec.ts -
import { TestBed, ComponentFixture, async } from '#angular/core/testing';
import * as angular from '#angular/upgrade/src/common/angular1';
import { UpgradeModule, setAngularJSGlobal } from '#angular/upgrade/static';
import { AppComponent } from './app.component';
import { AppSharedModule } from "../../../app-shared/src/lib/app-shared.module";
import { WatchlistComponent } from './watchlist/watchlist.component';
import { WatchlistFooterComponent } from './watchlist/watchlist-footer/watchlist-footer.component';
import { WatchlistHeaderComponent } from './watchlist/watchlist-header/watchlist-header.component';
import { WatchlistCardsComponent } from './watchlist/watchlist-cards/watchlist-cards.component';
import { WatchlistCardComponent } from "./watchlist/watchlist-cards/watchlist-card/watchlist-card.component";
import { WatchlistCardsModule } from './watchlist/watchlist-cards/watchlist-cards.module';
import { WatchlistModule } from './watchlist/watchlist.module';
import { ContextPanelApi } from 'shared/directives/oprContextPanel/oprContextPanel/oprContextPanelApi.service';
import { CiContextDataService } from '../../../../../../shared/shared-html/js/services/ciContextData.service';
import { CiContextMenuService } from '../../../app-shared/src/lib/ci-context-menu.service';
import { HttpClientModule, HttpClientXsrfModule } from '#angular/common/http';
import { Ng1AdaptersModule } from '../../../ng1-adapters/ng1-adapters.module';
import { FormsModule } from '#angular/forms';
import { BusyOverlayModule } from '../../../app-shared/src/lib/busy-overlay/busy-overlay.module';
import { L10nTranslationModule } from '../../../app-shared/src/lib/l10n-translation/l10n-translation.module';
import '../../../../../../shared/shared-html/test/config/index-mock.js';
import { Oprl10nPipe } from "../../../app-shared/src/lib/l10n-translation/oprl10n.pipe";
import { of } from 'rxjs';
export class MockBusyOverlayModule {
}
export class MockContextPanelApi {
}
export class MockCiContextDataService {
}
export class MockCiContextMenuService {
}
export class Oprl10nPipeStub {
public get(key: any): any {
return of(key);
}
public transform(key: any): any {
return of(key);
}
}
setAngularJSGlobal(angular);
describe('AppComponent', () => {
window['getAppConstants'] = function () {
return JSON.stringify({
topazWebContext: "",
mashupParams: { uim_sourceId: "0" },
staticContext: "/base",
locale: "en-us",
oprWebContext: ""
});
};
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
UpgradeModule,
BusyOverlayModule,
HttpClientModule,
AppSharedModule,
// appConstantsUtil,
// WatchlistModule,
Ng1AdaptersModule,
L10nTranslationModule,
// WatchlistModule
// WatchlistCardsModule
],
providers: [
{ provide: Oprl10nPipe, useClass: Oprl10nPipeStub },
// { provide: BusyOverlayModule, useClass: MockBusyOverlayModule }
{ provide: ContextPanelApi, useClass: MockContextPanelApi },
{ provide: CiContextDataService, useClass: MockCiContextDataService },
{ provide: CiContextMenuService, useClass: MockCiContextMenuService },
// { provide: appConstantsUtil }
],
declarations: [
AppComponent,
WatchlistComponent,
WatchlistFooterComponent,
WatchlistHeaderComponent,
WatchlistCardComponent,
WatchlistCardsComponent
]
// imports: [
// WatchlistModule
// ]
}).compileComponents();
}));
beforeEach(() => {
window['getAppConstants'] = function () {
return JSON.stringify({
topazWebContext: "",
mashupParams: { uim_sourceId: "0" },
staticContext: "/base",
locale: "en-us",
oprWebContext: ""
});
};
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create the app', () => {
expect(component).toBeTruthy();
});
});
My angular js version is 1.6 and Angular 7, as I said I am testing angular 7 components that use angular js components.
I found some links on web -
Angular Hybrid Error: Trying to get the AngularJS injector before it being set
https://github.com/angular/angular/issues/23141
but no help. I am not able to find anything in the angular doc as well.
Please guide.
I solved this by adding
const upgrade = TestBed.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document);
const serviceWhichReliesonInjector =
to my beforeEach Method.
afterwards i could simply access the service by
TestBed.get(ServiceWhichReliesonInjector)
I'm new to Angular5 and TypeScript, so it's very possible it's a simple thing I'm overlooking.
I have an Angular hybrid app that uses ngUpgrade to run AngularJS and Angular5 side-by-side. I'm trying to inject $templateCache into the OnAppInit function so that I can load all the AngularJS HTML templates before the app completely initializes. I'm getting the error "Cannot find name '$templateCacheService'" as indicated below. Is my syntax wrong or is this not possible?
I "upgrade" $templateCache in upgraded-providers.ts like this:
import { InjectionToken, Directive, ElementRef, Injector } from '#angular/core';
import { UpgradeComponent } from '#angular/upgrade/static';
export const $templateCacheService = new InjectionToken<any>('$templateCacheService');
export const $templateCacheServiceProvider = {
provide: $templateCacheService,
useFactory: (i: any) => i.get('$templateCache'),
deps: ['$injector']
};
Then in app.module.ts, I try to inject it into OnAppInit:
import { NgModule, APP_INITIALIZER, Inject } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { MatCommonModule } from '#angular/material';
import { FlexLayoutModule } from '#angular/flex-layout';
import { HttpClientModule, HttpClient, HTTP_INTERCEPTORS } from '#angular/common/http';
import { downgradeInjectable, UpgradeModule, downgradeComponent } from '#angular/upgrade/static';
import { environment } from '../environments/environment';
import {
$templateCacheServiceProvider,
$templateCacheService
} from './upgraded-providers';
import { AppComponent } from './app.component';
import { GlobalVarsService } from './core/global-vars.service';
import { WinAuthInterceptor } from './core/interceptors/win-auth.interceptor';
declare var angular: any;
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
MatCommonModule,
FlexLayoutModule,
HttpClientModule,
UpgradeModule
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: WinAuthInterceptor,
multi: true
},
{
provide: APP_INITIALIZER,
useFactory: OnAppInit,
multi: true,
deps: [GlobalVarsService, HttpClient, $templateCacheService]
},
GlobalVarsService,
$templateCacheServiceProvider
]
})
export class AppModule {
constructor(private upgrade: UpgradeModule, private http: HttpClient) { }
ngDoBootstrap() {
angular.module('app').factory('globalVars', downgradeInjectable(GlobalVarsService));
this.upgrade.bootstrap(document.body, ['app'], { strictDi: true });
}
}
////// THIS NEXT LINE GETS error TS2304: Cannot find name '$templateCacheService' /////
export function OnAppInit(globalVars: GlobalVarsService, http: HttpClient, $templateCache: $templateCacheService) {
return (): Promise<any> => {
return new Promise((resolve, reject) => {
http.get(environment.apiBase + '/api/meta/data').subscribe(x => {
globalVars.MetaData = x;
globalVars.VersionNumber = globalVars.MetaData.versionNumber;
globalVars.IsDebugBuild = globalVars.MetaData.isDebugBuild;
globalVars.User = globalVars.MetaData.user;
globalVars.ApiBase = environment.apiBase;
globalVars.Templates.forEach(template => {
$templateCache.put(template.Item1, template.Item2);
});
resolve();
});
});
};
}
This is TypeScript type error, it doesn't affect how the application works (as long as compilation errors are ignored).
templateCacheService is not a valid type here, because $templateCacheService is a variable (injection token), not a type or an interface.
Only Angular class constructors are annotated with types for DI. Since factory functions are annotated with deps property, types in function signature exist only to provide type safety. If it's not needed, types can be skipped:
export function OnAppInit(
globalVars: GlobalVarsService, http: HttpClient,
$templateCache
) { ... }
Otherwise proper types should be used. $templateCache is an object with get, put, etc methods. Appropriate types are provided with AngularJS #types/angular type definitions. It will be something like:
export function OnAppInit(
globalVars: GlobalVarsService, http: HttpClient,
$templateCache: ng.ITemplateCacheService
) { ... }
I have trying to implement auth provider for Node application which uses JWT
I'm getting error
TypeError: Cannot read property 'set' of undefined
My app.module.ts look like below.
import { BrowserModule } from '#angular/platform-browser';
import { ErrorHandler, NgModule } from '#angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { LoginPage } from '../pages/login/login';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { HttpModule } from '#angular/http';
import { Auth } from '../providers/auth/auth';
import { Storage } from '#ionic/storage';
export function provideStorage() {
return new Storage( { name: '__mydb' } /* optional config */);
}
#NgModule({
declarations: [
MyApp,
HomePage,
LoginPage
],
imports: [
BrowserModule,
IonicModule.forRoot(MyApp),
HttpModule,
// IonicStorageModule.forRoot({
// name: '__mercury',
// driverOrder: ['indexeddb', 'websql']
// })
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage,
LoginPage
],
providers: [
StatusBar,
SplashScreen,
LoginPage,
{ provide: Storage, useFactory: provideStorage },
{ provide: ErrorHandler, useClass: IonicErrorHandler },
Auth
]
})
export class AppModule { }
I used documentation in https://github.com/driftyco/ionic-storage/tree/v2.0.1#configuring-storage-new-in-117
My auth.provider.ts
import { Injectable } from '#angular/core';
import { Http, Response, Headers } from '#angular/http';
import 'rxjs';
import { Storage } from '#ionic/storage';
/*
Generated class for the AuthProvider provider.
See https://angular.io/docs/ts/latest/guide/dependency-injection.html
for more info on providers and Angular 2 DI.
*/
#Injectable()
export class Auth {
baseUrl: string = "http//localhost:9080/"
constructor(public http: Http, public storage: Storage) {
console.log('Hello AuthProvider Provider');
}
createAuthorizationHeader(headers: Headers) {
let token;
this.storage.get('token').then(data => token = data);
headers.append('Athorization', token);
}
login(data) {
return this.http.post('//localhost:9080/auth', data)
.map(this.extractData);
}
isLogged() {
this.storage.get('token').then(data => {
if (data)
return true;
else
return false;
}).catch(err => {
return false;
});
return false;
}
logout() {
this.storage.remove('token');
return true;
}
private extractData(res: Response) {
console.log(res);
let body = res.json();
if (body.success === true) {
this.storage.set("token", body.token);
};
return body || {};
}
}
My platform details are
Ionic Framework: 3.2.1
Ionic Native: ^3.5.0
Ionic App Scripts: 1.3.7
Angular Core: 4.1.0
Angular Compiler CLI: 4.1.0
Node: 6.10.3
OS Platform: macOS Sierra
Navigator Platform: MacIntel
Ionic Storage : ^2.0.1
Change
login(data) {
return this.http.post('//localhost:9080/auth', data)
.map(this.extractData);
}
to
login(data) {
return this.http.post('//localhost:9080/auth', data)
.map(this.extractData.bind(this));
}
or
login(data) {
return this.http.post('//localhost:9080/auth', data)
.map((data)=>this.extractData(data));
}
Your this is not refering to your component