Как сделать внедрение зависимости с сервисом в Angular 5? - PullRequest
0 голосов
/ 12 ноября 2018

Как сделать внедрение зависимостей с помощью сервиса?

Я получил уведомление о машинописи:

[Angular] Не удается разрешить все параметры для LandingComponent в landing.component.ts: ([объект Объект],?).


Обновление

Я не должен просто использовать LangService в конструкторе следующим образом:

private _langService: LangService;

Потому что LangService - это реализация. В реальном случае будет мало реализаций, таких как LangMockedSerives, langService_01, langService_02. При этом компонент посадки должен знать о реализации и работать только с интерфейсами.


Сервис и его интерфейс

export interface ILangService {
}

export class LangService implements ILangService {
}

Компонент

import { ILangService } from '../../services/Ilang.service';

@Component({
    selector: 'app-landing',
    templateUrl: './landing.component.html',
    styleUrls: ['./landing.component.less']
})

export class LandingComponent {
    private langService: ILangService
    constructor(
        private http: HttpClient,
        _langService: ILangService;
    ) {
        this._langService = langService;
    }
}

app.module.ts

import { ILangService } from './services/Ilang.service';
import { LangService } from './services/Lang.service';

@NgModule({
  declarations: [
    AppComponent,
    LandingComponent,
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    RouterModule.forRoot([
      { path: '', component: LandingComponent },
    ], { useHash: false }),
  ],
  providers: [
    LangService
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Ответы [ 3 ]

0 голосов
/ 12 ноября 2018

service.ts

import { Injectable } from '@angular/core';
import { HttpClient, Response, RequestOptions, Headers } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

export interface ILangService {
}

 @Injectable()   
export class LangService implements ILangService {

 constructor(private http: HttpClient) {  <-- httpclient for angular6
  }

getData(): Observable<any[]> {
return this.http.get('https://..../');
.map(this.extractData)
 .catch(this.handleError);
 }

private extractData(res: Response) {
const body = res.json();
return body || [];
}

private handleError(error: any) {
const errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error(errMsg);
console.log('Error....!');
 return Observable.throw(errMsg);
}
}

Компонент: -

import { LangService } from '../../services/lang.service'; <-- Import sevice here

@Component({
selector: 'app-landing',
templateUrl: './landing.component.html',
styleUrls: ['./landing.component.less']
})

 export class LandingComponent {
constructor(
private http: HttpClient,
_langService: LangService  <--- service
) { }

ngOnInit() {
let thisx = this;
this._langService.getData().subscribe(
function (success) {
// alert here on success
alert (success);
},
 error => console.log('Getting Server Data Error :: ' + 
JSON.stringify(error)));
}
}
0 голосов
/ 12 ноября 2018

LangService следует удалить из провайдеров app.module.ts:

@NgModule({
  declarations: [
    AppComponent,
    LandingComponent,
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    RouterModule.forRoot([
      { path: '', component: LandingComponent },
    ], { useHash: false }),
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

И интерфейс должен быть добавлен к провайдерам в компоненте:

import { LangService } from '../../services/Lang.service';
import { ILangService } from '../../services/ILang.service';

@Component({
    selector: 'app-landing',
    templateUrl: './landing.component.html',
    styleUrls: ['./landing.component.less'],
    providers: [
        { provide: ILangService, useClass: LangService }
    ]
})

export class LandingComponent {
    private langService: ILangService
    constructor(
        private http: HttpClient,
        _langService: ILangService;
    ) {
        this._langService = langService;
    }
}
0 голосов
/ 12 ноября 2018

Обновленный ответ

Если вы хотите использовать разные реализации для одной и той же службы, вы должны создать InjectionToken и предоставить правильную реализацию для вашего интерфейса в объявлениях вашего модуля.

Интерфейс - lang.service.ts

Создать токен впрыска, который будет распознаваться инжектором, набранным с ILangService interface

export const LangService = new InjectionToken<ILangService>('LangService');

export interface ILangService { }

1-й модуль - english.module.ts

Укажите EnglishLangService для токена инъекции LangService, где EnglishLangService реализует ILangService интерфейс

import { LangService } from './services/lang.service';
import { EnglishLangService } from './services/english-lang.service';

@NgModule({
  declarations: [ LandingComponent ],
  providers: [
    { provide: LangService, useClass: EnglishLangService }
  ]
})
export class EnglishModule { }

2-й модуль - french.module.ts

Укажите FrenchLangService для токена инъекции LangService, где FrenchLangService реализует ILangService интерфейс

import { LangService } from './services/lang.service';
import { FrenchLangService } from './services/french-lang.service';

@NgModule({
  declarations: [ LandingComponent ],
  providers: [
    { provide: LangService, useClass: FrenchLangService }
  ]
})
export class FrenchModule { }

Компонент - landing.component.ts

Таким образом, вы можете вставить LangService в ваш компонент, и инжектор получит реализацию, предоставленную в вашем модуле

import { LangService } from '../../services/lang.service';

@Component({
    selector: 'app-landing',
    templateUrl: './landing.component.html',
    styleUrls: ['./landing.component.less']
})
export class LandingComponent {
    constructor(
        private http: HttpClient,
        private langService: LangService,
    ) { }
}

Тестирование - mock-lang.service.ts

При тестировании вы сможете предоставить макетную реализацию таким же образом, как вы предоставляете правильную реализацию в своих прикладных модулях

import { LangService } from './services/lang.service';
import { MockLangService } from './services/mock-lang.service';

TestBed.configureTestingModule({
  providers: [
    { provide: LangService, useClass: MockLangService },
  ],
});

Оригинальный ответ

Вы должны импортировать свой сервис с классом вместо интерфейса

import { LangService } from '../../services/lang.service';

@Component({
    selector: 'app-landing',
    templateUrl: './landing.component.html',
    styleUrls: ['./landing.component.less']
})
export class LandingComponent {
    constructor(
        private http: HttpClient,
        private langService: LangService;
    ) { }
}

Также не забудьте установить декоратор @Injectable() в объявлении класса обслуживания

import { Injectable } from '@angular/core';

@Injectable()
export class LangService implements ILangService { }

И, конечно, вы должны предоставить услугу вашему модулю

import { LangService } from './services/Lang.service';

@NgModule({
  declarations: [
    AppComponent,
    LandingComponent,
  ],
  imports: [ ... ],
  providers: [
    LangService
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Вы можете прочитать о внедрении угловой зависимости здесь: https://angular.io/guide/dependency-injection

Еще одна интересная ссылка для предварительных объявлений об услугах: https://offering.solutions/blog/articles/2018/08/17/using-useclass-usefactory-usevalue-useexisting-with-treeshakable-providers-in-angular/

...