Угловой 2 Инжектированный сервис не определен
Почему мое служение (это.loggerService) undefined в моем DataHandlerService, когда он был введен? Я думал, что инъекция зависимости позаботилась об этом. Мой loggerService работает в других службах. Пожалуйста, помогите мне понять, где я ошибаюсь. Мой код DataHandlerService ниже:
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { LoggerService } from './logger.service';
@Injectable()
export class DataHandlerService
{
constructor(private loggerService: LoggerService)
{
}
extractData(res: Response)
{
let body = res.json();
return body || {};
}
handleHttpError(error: any)
{
let errMsg = (error.message) ? error.message : error.status ? `${error.status} - ${error.statusText}` : 'Server error';
if (errMsg && this.loggerService) //Why is this.loggerService always undefined?
{
this.loggerService.error(errMsg);
}
return Observable.throw(errMsg);
}
}
Мой код LoggerService ниже:
import { Injectable } from '@angular/core';
import { Http, Headers, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { ConfigurationService } from './configuration.service';
@Injectable()
export class LoggerService
{
constructor(private http: Http, private configurationService: ConfigurationService)
{
}
public fatal(msg: string)
{
if (msg)
{
this.log(msg, "Fatal");
}
}
public debug(msg: string)
{
if (msg)
{
this.log(msg, "Debug");
}
}
public info(msg: string)
{
if (msg)
{
this.log(msg, "Info");
}
}
public warn(msg: string)
{
if (msg)
{
this.log(msg, "Warn");
}
}
public error(msg: string)
{
if (msg)
{
this.log(msg, "Error");
}
}
private log(msg: string, logLevel: string)
{
if (msg && logLevel && this.configurationService && this.configurationService.coreSettings)
{
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
let loggingInfo: LoggingInfo = { "message": msg, "logLevel": logLevel, "sourceName": "CoreIV", "logDirectory": this.configurationService.coreSettings.logDirectory };
this.http.post(this.configurationService.coreSettings.logbookUrl + "/rest/LogMessage", { loggingInfo }, { headers: headers })
.toPromise()
.then(res => this.extractData(res))
.catch(err => this.handleHttpError(err));
}
}
private extractData(res: Response)
{
let body = res.json();
return body || {};
}
private handleHttpError(error: any)
{
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
return Observable.throw(errMsg);
}
}
export interface LoggingInfo
{
message: string,
logLevel: string,
sourceName: string,
logDirectory: string
}
Мое Приложение.Код модуля ниже:
import { NgModule, APP_INITIALIZER, ErrorHandler } from '@angular/core';
import { LocationStrategy, HashLocationStrategy } from '@angular/common';
import { HttpModule, JsonpModule, Jsonp } from '@angular/http';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, FormGroup, FormControl, ReactiveFormsModule } from '@angular/forms';
import { routing, appRoutingProviders } from './app.routing';
import { AppConfig } from './app.config';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { AppErrorHandler, LOGGING_ERROR_HANDLER_OPTIONS, LOGGING_ERROR_HANDLER_PROVIDERS } from './app.error-handler';
import { AppService } from './app.service';
import { ConfigurationService } from './shared/services/configuration.service';
import { DataHandlerService } from './shared/services/data-handler.service';
import { LoggerService } from './shared/services/logger.service';
import { AuthGuard } from './auth-guard.service';
export function init_app(appConfig: AppConfig, configurationService: ConfigurationService, loggerService: LoggerService)
{
// Do initiating of services that are required before app loads
// NOTE: this factory needs to return a function (that then returns a promise)
return appConfig.load()
.then((res) =>
{
configurationService.coreSettings = appConfig.config;
})
.catch((err) =>
{
loggerService.error(err);
});
}
@NgModule({
imports: [
BrowserModule,
FormsModule,
routing,
HttpModule,
JsonpModule
],
exports: [
],
declarations: [
HomeComponent,
AppComponent
],
providers: [
HttpModule,
ConfigurationService,
LoggerService,
{ provide: LocationStrategy, useClass: HashLocationStrategy },
LOGGING_ERROR_HANDLER_PROVIDERS,
{
provide: LOGGING_ERROR_HANDLER_OPTIONS,
useValue: {
rethrowError: false,
unwrapError: true
}
},
appRoutingProviders,
AuthGuard,
DataHandlerService,
AppConfig,
{
provide: APP_INITIALIZER,
useFactory: init_app,
deps: [AppConfig, ConfigurationService, LoggerService],
multi: false
}
],
bootstrap: [AppComponent, appRoutingProviders]
})
export class AppModule
{
constructor(private httpModule: HttpModule)
{
}
}
3 ответа:
Я нашел решение этого вопроса. Ответ в посте angular 2-Injected service in http error handler указал мне в правильном направлении. Я использовал следующее:
.map(this.dataHandler.extractData) .catch(this.dataHandler.handleHttpError);
Но следует использовать:
.map(res => this.dataHandler.extractData(res)) .catch(err => this.dataHandler.handleHttpError(err));
По какой-то причине лямбды необходимы.
Это происходит со мной, когда я не могу импортировать сервис в основной модуль приложения и перечислить его в разделе провайдеры
// in app.module.ts import { LoggerService } from './logger.service'; ... @NgModule({ ... providers: [ LoggerService,
Несмотря на то, что ответ верен и принят, я хотел бы записать причину, по которой это не удалось, и другое возможное решение.
Вместо того, чтобы писать
.map(this.dataHandler.extractData) .catch(this.dataHandler.handleHttpError);
Вы можете использовать
.map(this.dataHandler.extractData.bind(this)) .catch(this.dataHandler.handleHttpError.bind(this));
Основная причина, по которой это не удалось, заключается в том, что
this
принимает значение, основанное на контексте выполнения, и если служба была вызвана вsetTimeout
илиsetInterval
, как в моем случае, значениеthis
былоundefined
(из - за строгого режима-в противном случае это был бы Объектwindow
). Используя.bind
вы явно предоставляете значениеthis
(объект класса компонента).