サービス(this.loggerService)が挿入されたときに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
}
以下の私のApp.Moduleコード:
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)
{
}
}
この問題の解決策を見つけました。投稿の回答 angular 2-HTTPエラーハンドラーに注入されたサービス は、正しい方向を示してくれました。私は次を使用していました:
.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
(コンポーネントクラスオブジェクト)の値を明示的に指定できます。