Угловой обмен данными с компонентами, использующими сервис - PullRequest
0 голосов
/ 02 октября 2018

В моем угловом интерфейсе 2 службы, одна для вызовов API и одна для обмена данными двумя разными компонентами.Таким образом, вторая служба использует службу API.

Если я использую только службу API и подписываю свои Observables внутри моего компонента, все работает нормально (см. Xxx.component.html).

Поэтому, если я объявлю эти две службы в качестве провайдеров внутри app.module и добавлю API-службу в службу общего доступа, она больше не будет работать.

Используя отладчик, я всегда получаю переменную "tmp", не определенную вsettings.service.ts

Я знаю, я мог бы сделать это также с помощью @Input для дочерних компонентов, но я думаю, что использование службы гораздо удобнее и для развязки компонентов.

Любые предложения:)?

Ниже моего кода:

api.service.ts

export class ApiService {
    API_URL = 'https://localhost:44381/api/v1';
    constructor(private httpClient: HttpClient) { }

    /** GET settings from API*/
    getSettings(): Observable<Setting[]> {
        return this.httpClient.get<Setting[]>(this.API_URL + '/settings')
        .pipe(
          catchError(this.handleError('getSettings', [])));
    }
}

settings.service.ts

export class SettingsService {

   tmp: Setting[];

   constructor(private apiService: ApiService) { }

   getSettings(): void {
       this.apiService.getSettings()
         .subscribe(settings =>
           this.tmp = settings);
   }

   getData(): Setting[] {
       this.getSettings();
       return this.tmp;
   }
}

settings.component.ts

export class SettingsComponent implements OnInit {
    settings: Setting[];

    constructor(private settingService: SettingsService) { }

    // Load Setting while starting
    ngOnInit() {
        // this.getSettings();
        this.settings = this.settingService.getData();
    }

    // old code when using only API service which works..
    /*getSettings(): void {
        this.apiService.getSettings()
          .subscribe(settings => this.settings = settings);
    }*/
}

settings.component.hmtl

<div>
    <table>
    <tr>
      <th>keyname</th>
      <th>value</th>
      <th>defaultValue</th>
      <th align="right">text</th>
    </tr>

    <tr *ngFor="let s of settings">
      <td>{{s.keyName}}</td>
      <td>{{s.wert}}</td>
      <td>{{s.defaultValue}}</td>
      <td align="right">{{s.description}}</td>
    </tr>
    </table>
</div>

1 Ответ

0 голосов
/ 02 октября 2018

Ваша проблема заключается в асинхронной функциональности.Метод subscribe используется для ожидания асинхронной операции.Это означает, что когда вы выполняете конкретный запрос, например удаленный, вы не хотите останавливать выполнение всего потока в ожидании ответа.Но вместо этого вы хотите выполнить запрос и выполнить весь другой код в то время, когда сервер обрабатывает ваш запрос и отправляет ответ.

Итак, давайте проанализируем, как протекает выполнение этого кода

getSettings(): void {
       this.apiService.getSettings()
         .subscribe(settings =>
           this.tmp = settings);
   }

getData(): Setting[] {
       this.getSettings();
       return this.tmp;
   }
  1. this.getSettings() выполняет запрос и подписывается на его ответ
  2. , затем, пока он все еще ожидает подписанного ответа, вы немедленно возвращаете this.tmp, который по-прежнему не определен
  3. через некоторое время ваш подписанный запрос заканчивается, вы получаете свой ответ и присваиваете это значение вашей this.tmp переменной

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

Возможное решение с темой

Сервис

export class SettingsService {

   API_URL = 'https://localhost:44381/api/v1';

   settingsSource = new Subject<Setting>();
   settings$ = this.settingsSource.asObservable();

   constructor(private httpClient: HttpClient) { }

   getSettings(): void {
       this.apiService.getSettings().subscribe(settings =>
           this.settingsSource.next(settings);
       );
   }

   getData(): Setting[] {
       this.getSettings();
       return this.tmp;
   }

   get result$(): Observable<Setting> {
      return this.settings$;
   }
}

Компонент

export class SettingsComponent implements OnInit {

    subscription: Subscription;
    settings: Setting[];

    constructor(private settingService: SettingsService) { }

    // Load Setting while starting
    ngOnInit() {

        // subscribe for settings
        this.resSubscription = this.searchService.result$.subscribe(result => {
            this.resList = result.result;
        });

        // request settings
        this.settings = this.settingService.getData();
    }
}

Как видите, SettingsComponent подписаться наsettings$ Observable ($ - это соглашение для Observable), затем он запрашивает данные для службы.Когда служба получает ответные данные, помещает их в settingsSource, это Observable версия (settings$) получает данные, и всем подписанным компонентам сообщается

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