Как мне использовать один и тот же экземпляр службы среди всех компонентов лениво загружаемого модуля?

У меня есть корневой модуль под названием «AppModule». «AppModule» лениво загружает несколько других модулей, один из которых называется «BooksAndRunModule». У меня есть два компонента, принадлежащие «BooksAndRunModule», которые должны совместно использовать один и тот же экземпляр службы, которую я назвал «BooksAndRunService». Первое и единственное место, где я объявляю «BooksAndRunService» в качестве поставщика, находится в «BooksAndRunModule». Я думал, что при этом мои два компонента будут иметь доступ к одному и тому же экземпляру службы, но это не так. Очевидно, что мое понимание внедрения зависимостей не соответствует действительности. Я не хочу, чтобы эта служба была доступна для всего приложения, поэтому я объявляю ее поставщиком только в «BooksAndRunModule». Что я не понимаю и как я могу заставить это работать? Дайте мне знать, если вы хотели бы видеть любой другой файл в моем проекте.

Модуль приложения:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppRoutingModule } from './app-routing.module';
import { AuthenticationModule } from './authentication/authentication.module';
import { SharedModule } from './shared/shared.module';


import { AppComponent } from './app.component';
import { FriendService } from './friend.service';




@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    AppRoutingModule,
    AuthenticationModule,
    SharedModule,
  ],
  providers: [ FriendService ],
  bootstrap: [AppComponent]
})


export class AppModule { }

Модуль БуксАндРун:

import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';

import { SharedModule } from '../shared/shared.module';

import { FriendService } from '../friend.service';
import { BooksAndRunCreateComponent } from './books_and_run_create.component';
import { BooksAndRunPlayComponent } from './books_and_run_play.component';
import { BooksAndRunService } from './books_and_run.service';

import { BooksAndRunRouter } from './books_and_run.router';



@NgModule({
  declarations: [
    BooksAndRunCreateComponent,
    BooksAndRunPlayComponent,
  ],
  imports: [
    CommonModule,
    SharedModule,
    BooksAndRunRouter,
  ],
  providers: [  FriendService, BooksAndRunService ],
})


export class BooksAndRunModule { }

Компонент BooksAndRunCreateComponent:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

import { FriendList } from '../friendlist';
import { FriendService } from '../friend.service';
import { BooksAndRunService } from './books_and_run.service';


@Component({
  moduleId: module.id,
  selector: 'books-and-run-create',
  templateUrl: './books_and_run_create.component.html',
  styleUrls: ['./books_and_run_create.component.css'],
})


export class BooksAndRunCreateComponent implements OnInit {
  constructor(public friendService: FriendService, private booksAndRunService: BooksAndRunService, private router: Router) { }

  isRequesting: boolean;
  name: string = 'Aaron';
  friendList: FriendList[] = [];
  players: any[] = [];

  private stopRefreshing() {
    this.isRequesting = false;
  }


  ngOnInit(): void {
    this.booksAndRunService.resetPlayers();
    this.isRequesting = true;
    this.friendService
      .getFriendList()
        .subscribe(
          data => this.friendList = data,
          () => this.stopRefreshing(),
          () => this.stopRefreshing(),
        )
  }

  addPlayer(player): void {
    this.booksAndRunService.addPlayer(player);
    for(var i=0; i<this.friendList.length; i++) {
            if(this.friendList[i].pk === player.pk) {
                this.friendList.splice(i, 1);
            }
        }
    this.players = this.booksAndRunService.getPlayers();
    console.log("Current players are: " + this.players);
  }

  removePlayer(player): void {
    this.booksAndRunService.removePlayer(player);
    this.friendList.push(player);
    this.players = this.booksAndRunService.getPlayers();
    console.log("Current players are: " + this.players)
  }

  goToGame(): void {
    console.log('Going to game with players: ' + this.booksAndRunService.getPlayers());
    this.router.navigate(['/books_and_run/play'])
  }



}

Компонент BooksAndRunPlay:

import { Component, OnInit, AfterViewChecked } from '@angular/core';
import { BooksAndRunService } from './books_and_run.service';
import { Score } from './books_and_run.classes';



@Component({
  moduleId: module.id,
  selector: 'books-and-run-play',
  templateUrl: './books_and_run_play.component.html',
  styleUrls: ['./books_and_run_play.component.css'],
})


export class BooksAndRunPlayComponent implements OnInit, AfterViewChecked {
  constructor(public booksAndRunService: BooksAndRunService) { }

  game = { players: []};



  ngOnInit(): void {
    console.log("Initalizing BooksAndRunPlayComponent...")
    console.log("Here are the players: " + this.booksAndRunService.getPlayers())
    var game: any;

    if(localStorage.getItem('game') === null) {
      console.log("Creating a new game...");
      this.game = this.booksAndRunService.prepareGame();
      this.booksAndRunService.saveGame(this.game);
    } else {
        console.log("Restoring game from localStorage...");
        this.game = this.booksAndRunService.restoreGame();
    };

  }

  ngAfterViewChecked() {
    this.booksAndRunService.saveGame(this.game);
  }

}

BooksAndRunService:

import { Injectable } from '@angular/core';
import { Headers, Http } from '@angular/http';
import { Game, Player, Score, Round } from './books_and_run.classes'


@Injectable()
export class BooksAndRunService {

    players: Player[];

    getPlayers() {
        return this.players;
    }

    addPlayer(player) {
        this.players.push(player);
    }

    removePlayer(player) {
        for(var i=0; i<this.players.length; i++) {
            if(this.players[i].pk === player.pk) {
                this.players.splice(i, 1);
            }
        }
    }

    resetPlayers() {
        this.players = [];
    }

}

person FlashBanistan    schedule 10.03.2017    source источник
comment
Я удалил свой ответ, так как это был неправильный ответ. Вам не нужно передавать их между братьями и сестрами. Вполне достаточно объявить службу в массиве провайдеров модуля. Что указывает на то, что вы получаете другой экземпляр службы? Взгляните на этот вопрос.   -  person J. Adam Connor    schedule 11.03.2017
comment
Массив «игроков» в сервисе заполняется, когда я создаю игру, но как только я перехожу к BooksAndRunPlayComponent и пытаюсь вывести игроков из сервиса, он говорит, что он пуст.   -  person FlashBanistan    schedule 11.03.2017
comment
Похоже, вы очищаете массив игроков в хуке жизненного цикла OnInit в своем компоненте создания. Я не вижу, где вы заполняете этот массив.   -  person J. Adam Connor    schedule 11.03.2017
comment
Когда вы переходите к компоненту воспроизведения, что console.log("Here are the players: " + this.booksAndRunService.getPlayers()) регистрирует?   -  person J. Adam Connor    schedule 11.03.2017
comment
Он говорит, что он не определен. Но прямо перед тем, как я покину компонент создания, он показывает игроков, которых я добавил. До того, как я реализовал ленивую загрузку, все работало нормально.   -  person FlashBanistan    schedule 11.03.2017
comment
Посмотрите ответ здесь. Это то, что вам нужно.   -  person J. Adam Connor    schedule 11.03.2017
comment
На самом деле я нашел ответ, похожий на ссылку, которая у вас есть здесь, и пытался его опробовать. Я проверю и отчитаюсь.   -  person FlashBanistan    schedule 11.03.2017
comment
Подробнее здесь.   -  person J. Adam Connor    schedule 11.03.2017
comment
Пока я безуспешен. Я попробую еще раз, когда вернусь с работы, и отчитаюсь здесь. Спасибо за помощь, по крайней мере, теперь я иду в правильном направлении.   -  person FlashBanistan    schedule 11.03.2017
comment
Давайте продолжим обсуждение в чате.   -  person J. Adam Connor    schedule 11.03.2017


Ответы (2)


В конструкторе BooksAndRunPlayComponent сделайте сервис общедоступным и не объявляйте его в своем BooksAndRunCreateComponent.

Получите к нему доступ через компоненты и попробуйте.

В качестве альтернативы, используйте его на уровне модуля как

static forRoot(): BooksAndRunModule {
        return {
            providers: [BooksAndRunService]
        };
    }
person Aravind    schedule 10.03.2017
comment
Ваше первое предложение не работает, а что касается вашего второго предложения, почему BooksAndRunModule не может быть родителем? - person FlashBanistan; 11.03.2017
comment
проверьте обновленный - person Aravind; 11.03.2017

Самый простой ответ — просто предоставить эту услугу в массиве поставщиков в модуле приложения.

@NgModule({
    providers: [ BooksAndRunService ]
})
class AppModule {}

Причина этого хорошо освещена здесь в сборнике официальных объяснений по этому вопросу. Короче говоря, модули с ленивой загрузкой имеют собственную корневую область. Вместо этого вы можете использовать forRoot(), но это, по сути, делает то же самое.

person J. Adam Connor    schedule 11.03.2017
comment
Собственно, так оно у меня сейчас и работает. Заглядывая в будущее, я могу иметь более 100 карточных игр как часть своего приложения. Никто не собирается играть во все 100 игр одновременно, поэтому нет смысла заранее загружать 100 разных игровых модулей и сервисов. Вот почему я хотел бы лениво загружать конкретный игровой модуль и соответствующий сервис и привязывать его только к этой игре. - person FlashBanistan; 11.03.2017
comment
Решение forRoot теоретически имеет смысл, но мне трудно понять, где и что добавить и удалить. - person FlashBanistan; 11.03.2017
comment
Служба этого модуля не должна быть доступна для любых активно загружаемых компонентов или модулей в приложении, но теоретически она должна быть доступна для его собственных компонентов, которые загружаются отложенно. Мне было бы интересно посмотреть, как выглядит BooksAndRunRouter. - person J. Adam Connor; 11.03.2017
comment
Но если я помещу 100 различных игровых сервисов в корневой app.module, это будет огромная трата ресурсов, когда пользователь будет использовать только 1 или 2 из них. Я могу опубликовать маршрутизатор через час или около того, когда я вернусь домой. - person FlashBanistan; 11.03.2017
comment
Не могли бы вы опубликовать код для BooksAndRunRouter? Мне интересно, возможно ли, что вы жадно загружаете компоненты, но лениво загружаете модуль... возможно ли это? Я не понимаю, как это сделать, но если компоненты загружены лениво, они должны получить экземпляр службы. - person J. Adam Connor; 11.03.2017
comment
Вот ссылка на весь репозиторий github, ссылка - person FlashBanistan; 11.03.2017