Как я могу ввести параметр из компонента в службу в Angular? - PullRequest
0 голосов
/ 04 марта 2020

Приветствия,

Пока я следовал руководству «Тур героев», я хотел немного поэкспериментировать с несколькими опциями массива данных и с каким heroesUrl я использую, чтобы запрашивать данные у InMemoryDbService. Я хотел бы иметь возможность передать параметр heroesUrl из компонента heroes в службу heroes, чтобы определить, какую партию героев я хотел бы получить из БД, но в консоли появляется следующее сообщение об ошибке:

vendor.js:14812 ERROR Error: Uncaught (in promise): NullInjectorError: R3InjectorError(AppModule)[HeroService -> heroesUrl -> heroesUrl -> heroesUrl]: 
  NullInjectorError: No provider for heroesUrl!
NullInjectorError: R3InjectorError(AppModule)[HeroService -> heroesUrl -> heroesUrl -> heroesUrl]: 
  NullInjectorError: No provider for heroesUrl!
    at NullInjector.get (vendor.js:10919)
    at R3Injector.get (vendor.js:24642)
    at R3Injector.get (vendor.js:24642)
    at R3Injector.get (vendor.js:24642)
    at injectInjectorOnly (vendor.js:10774)
    at Module.ɵɵinject (vendor.js:10784)
    at Object.HeroService_Factory [as factory] (main.js:503)
    at R3Injector.hydrate (vendor.js:24869)
    at R3Injector.get (vendor.js:24630)
    at NgModuleRef$1.get (vendor.js:41631)
    at resolvePromise (polyfills.js:806)
    at resolvePromise (polyfills.js:765)
    at polyfills.js:867
    at ZoneDelegate.invokeTask (polyfills.js:413)
    at Object.onInvokeTask (vendor.js:46107)
    at ZoneDelegate.invokeTask (polyfills.js:412)
    at Zone.runTask (polyfills.js:181)
    at drainMicroTaskQueue (polyfills.js:583)

В нем говорится, что для heroesUrl не существует провайдера, поэтому я подозреваю, что не правильно определяю провайдера в компоненте:

import { Component, OnInit } from "@angular/core";

import { Hero } from "../hero";
import { HeroService } from "../hero.service";
import { MessageService } from "../message.service";

@Component({
  selector: "app-heroes",
  templateUrl: "./heroes.component.html",
  styleUrls: ["./heroes.component.scss"],
  providers: [{ provide: "heroesUrl", useValue: "heroesTwo" }]  //<-------------
})
export class HeroesComponent implements OnInit {
  heroes: Hero[];

  constructor(
    private heroService: HeroService,
    public messageService: MessageService
  ) {}

  ngOnInit(): void {
    this.heroService.getHeroes().subscribe(heroes => (this.heroes = heroes));
  }
}

Так выглядит служба например, где я попытался ввести параметр:

import { Observable, of } from "rxjs";

import { HttpClient, HttpHeaders } from "@angular/common/http";
import { Injectable, Input, Inject, Optional } from "@angular/core";

import { Hero } from "./hero";
import { MessageService } from "./message.service";

import { catchError, map, tap } from "rxjs/operators";

@Injectable({
  providedIn: "root"
})
export class HeroService {
  constructor(
    private http: HttpClient,
    private messageService: MessageService,
    @Inject("heroesUrl") private heroesUrl: string //<-------------
  ) {}

  getHeroes(): Observable<Hero[]> {
    return this.http.get<Hero[]>(this.heroesUrl).pipe(
      tap(tappedData =>
        this.log("Fetched heroes: " + tappedData.map(data => data.name))
      ),
      catchError(this.handleError<Hero[]>("getHeroes", []))
    );
  }

  getHero(id: number): Observable<Hero> {
    const url = this.heroesUrl + "/" + id;
    return this.http.get<Hero>(url).pipe(
      tap(_ => this.log("fetched hero id=" + id)),
      catchError(this.handleError<Hero>("getHero id=" + id))
    );
  }

  private log(message: string) {
    this.messageService.add(`HeroService: ${message}`);
  }

  private handleError<T>(operation = "operation", result?: T) {
    return (error: any): Observable<T> => {
      console.error(error);
      this.log(`${operation} failed: ${error.body.error}`);
      return of(result as T);
    };
  }
}

В службе, которая перехватывает вызовы http, реализуя InMemoryDbService:

return { heroesOne: heroes1, heroesTwo: heroes2 };

Я смотрел, в частности, эти руководства :

Может кто-нибудь объяснить, что я делаю не так?

Ответы [ 2 ]

0 голосов
/ 04 марта 2020

Вам необходимо объявить ваш heroesUrl в поставщиках вашего app.module.ts, но тогда для каждой службы героев будет предоставлен один и тот же URL.

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [
    HeroService,
    { provide: "heroesUrl", useValue: "heroesOne" }
  ],
  bootstrap: [AppComponent]
})

Или вы объявите своего провайдера в компоненте, используя service и url тоже, и тогда каждый компонент будет иметь свой собственный сервис с собственным url.

@Component({
  selector: "app-heroes",
  templateUrl: "./heroes.component.html",
  styleUrls: ["./heroes.component.scss"],
  providers: [
    HeroService,
    { provide: "heroesUrl", useValue: "heroesTwo" }
  ]
})

И вы можете объединить эти два, чтобы иметь универсальный c HeroesService с URL-адресом heroesOne и другими HeroesService с другими URL для конкретных c компонентов.

0 голосов
/ 04 марта 2020

Добавьте эту строку -> поставщики: [{обеспечить: "heroesUrl", useValue: "heroesTwo"}] в массив поставщика файлов Module.ts вместо файла компонента ts и попробуйте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...