コンポーネント毎にサービスのインスタンス生成ができない

Angular+ASP.NET COREを使ったweb開発を行っています。
ページングに必要な情報をサービスとしておりまして、今後このサービスを色々な画面で使おうと思い、コンポーネント毎にインスタンスを生成しようと考えました。

restaurants-list-components.ts

import { PaginationService } from '../dataServices/pagination.service';

@Component({
  selector: 'restaurants',
  templateUrl: './restaurants-list-component.html',
  styleUrls: ["./restaurants-list-component.css"],
  providers: [PaginationService]
})
export class RestaurantListComponent implements OnInit{
  constructor(
    private paginationService: PaginationService,
  ) {
  }
#以下略
}

foods-list-components.ts

import { PaginationService } from '../dataServices/pagination.service';

@Component({
  selector: 'foods',
  templateUrl: './foods-list-component.html',
  providers: [PaginationService]
})
export class  FoodsListComponent implements OnInit{
  constructor(private paginationService: PaginationService) {}
#以下略

}


pagination.service.ts

import { Injectable } from '@angular/core';
import { PageEvent } from '@angular/material/paginator';

@Injectable()
export class PaginationService {

  private paginationModel: PaginationModel;

  get page(): number {
    return this.paginationModel.pageIndex;
  }

  set page(pageIndex) {
    this.paginationModel.pageIndex = pageIndex;
  }

  get orderBy(): string {
    return this.paginationModel.orderBy.trim();
  }
  get orderDirection(): string {
    return this.paginationModel.orderDirection.trim();
  }

  get filterKey(): string {
    return this.paginationModel.filterKey;
  }
  set filterKey(key) {
    this.paginationModel.filterKey = key;
  }

  get selectItemsPerPage(): number[] {
    return this.paginationModel.selectItemsPerPage;
  }

  get pageCount(): number {
    return this.paginationModel.pageSize;
  }

  constructor() {
    this.paginationModel = new PaginationModel();
  }

  init() {
    this.paginationModel.pageSize = this.selectItemsPerPage[0];
    this.paginationModel.pageIndex = 1;
    this.paginationModel.orderBy = '';
    this.paginationModel.orderDirection = '';
    this.paginationModel.filterKey = '';
    this.paginationModel.allItemsLength = 0;
  }


  change(pageEvent: PageEvent) {
    if (this.paginationModel.pageSize === pageEvent.pageSize) {
      this.paginationModel.pageIndex = pageEvent.pageIndex + 1;
    } else {
      this.paginationModel.pageIndex = 1;
    }
    this.paginationModel.pageSize = pageEvent.pageSize;
    this.paginationModel.allItemsLength = pageEvent.length;
  }

  filterChange(filterValue: string) {
    this.paginationModel.filterKey = filterValue.trim().toLowerCase();
  }

  sortChange(event) {
    this.paginationModel.orderDirection = event.direction;
    this.paginationModel.orderBy = event.active;
  }
}

export class PaginationModel {
  selectItemsPerPage: number[] = [10, 20, 50, 100];
  pageSize = this.selectItemsPerPage[0];
  pageIndex = 1;
  orderBy = '';
  orderDirection = '';
  filterKey = '';
  allItemsLength = 0;
}

このコードを実行したときに何も結果が表示されなくなったので、developer toolでPaginationServiceにカーソルを当てたところ、
@Componen内のproviders: [PaginationService]にてエラーが起きてしまいました。

エラーメッセージは以下の通りです。

"_dataServices_pagination_service__WEBPACK_IMPORTED_MODULE_6__ is not defined"

スタック内容は以下のとおりです。

"ReferenceError: _dataServices_pagination_service__WEBPACK_IMPORTED_MODULE_6__ is not defined
    at eval (eval at <anonymous> (http://localhost:57636/main.js:857:13), <anonymous>:1:1)
    at SafeSubscriber._next (http://localhost:57636/main.js:857:13)
    at SafeSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.__tryOrUnsub (http://localhost:57636/vendor.js:149039:16)
    at SafeSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.next (http://localhost:57636/vendor.js:148977:22)
    at Subscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._next (http://localhost:57636/vendor.js:148923:26)
    at Subscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (http://localhost:57636/vendor.js:148900:18)
    at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next (http://localhost:57636/vendor.js:153942:26)
    at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (http://localhost:57636/vendor.js:148900:18)
    at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/operators/filter.js.FilterSubscriber._next (http://localhost:57636/vendor.js:153381:30)
    at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (http://localhost:57636/vendor.js:148900:18)"

因みにapp.module.ts内のprovidersの定義にPaginationServiceは含まれております。
以上、よろしくおねがいします。

1 Like

おそらくサービスクラスの後で宣言されている PaginationModel をサービスの前に移すと解決かもしれません。
後にあるので、サービスの初期化時にまだ存在してなくてエラーになりそうです

と思ったんですが、違う気がしてきました。どこかで循環参照になっていたりしたらng build --aot のログで警告が出ていると思うのですが、AOTビルドのログを貼ってもらえると手がかりになりそうです。

あんまり関係ないかもしれませんが、@Componentprovidersにサービスを追加している場合はapp.module側のprovidersには設定しなくてもokです。コンポーネント側でprovidersを設定し忘れると、想定外にrootのPaginationServiceのインスタンスが参照されるので外しておいたほうがよさそうです。

1 Like

返信ありがとうございます。
ng build --aotを使用してビルドしてみたところ、以下のようなエラーが表示されました。

ERROR in src\app\restaurant\restaurant-list-component.html(54,22): : Property 'paginationService' is private and only accessible within class 'RestaurantListComponent'.
src\app\restaurant\restaurant-list-component.html(54,22): : Property 'pageSize' does not exist on type 'PaginationService'.
src\app\restaurant\restaurant-list-component.html(55,22): : Property 'paginationService' is private and only accessible within class 'RestaurantListComponent'.
src\app\food\food-list-component.html(48,22): : Property 'paginationService' is private and only accessible within class 'FoodListComponent'.
src\app\food\food-list-component.html(48,22): : Property 'pageSize' does not exist on type 'PaginationService'.
src\app\food\food-list-component.html(49,22): : Property 'paginationService' is private and only accessible within class 'FoodListComponent'.

ありがとうございます。
上のrootのproviderを見に行ってしまうんですね。

このエラーは、コンポーネントクラス側で private としているサービスにテンプレートからアクセスしているのが原因です。直接参照をやめて一旦コンポーネントのフィールドやgetterを挟むか、privateから protected などに変更すればテンプレートから参照できます。

しかし冒頭のエラーはこれとは別問題な気がしますね

ありがとうございます。
ng build --aotにて発生したエラーを解決し、全くエラーがない状態にすることができました。
lacolacoさんのおっしゃるとおり、privateで宣言されているサービスにテンプレートからアクセスしていたことが原因のエラーでした。
しかし、この実装が終わったあと、別の問題が発生してしまいました。
この問題は別のトピックでお話させてください。

以上、ありがとうございました。