Я думаю, что я неправильно использую подписчика BehaviorSubject. Может ли кто-нибудь показать мне лучший способ вызова данных из моего API в Angular2?

У меня есть пара кнопок навигации в приложении Angular. Я пытаюсь удалить "Предыдущая" на первой странице и "Следующая" на последней.

Все, что я хочу сделать, это установить два логических значения, которые говорят, будет ли это первая или последняя страница.

Беда в том, что мне не удалось разобраться с этими subscribers а также behaviours,

Я могу создать функцию, которая рассчитывает последнюю страницу из totalItems а также itemsPerPage так что, пожалуйста, не беспокойтесь об этом, я просто не знаю, как вызвать функцию из этой подписки.

Если кто-то может показать мне, как написать обратный звонок или что-то еще, что нужно для этого, я буду вечно благодарен.

Component.html:

<div class="pagination-panel clearfix">
    <button (click)="previousPage()" *ngIf="firstPage != true">Prev</button>
    <button (click)="nextPage()" *ngIf="lastPage != true">Next</button>
</div>

<!-- How the data is used, if that helps  -->
<h2 class="spray-header">Presenters</h2>
<article *ngFor="let presenter of (presenters$ | async)?.data" class="presenter-item">
    <div class="presenters-header">
        <h3 class="presenters-title margin-none">
            <a [routerLink]="['/presenters', presenter.id]">{{presenter.name | uppercase}}</a>
        </h3>
        <p class="presenters-details">{{presenter.details}}</p>
    </div>
    <img src="{{presenter.small_thumb}}" class="presenters-profile-picture profile-picture">
</article>

Component.ts

import {Component, OnInit, Inject} from '@angular/core';
import {Http} from "@angular/http";
import "rxjs/add/operator/map";
import {BehaviorSubject} from "rxjs/BehaviorSubject";
import {ActivatedRoute, Router} from "@angular/router";

export class PresentersComponent implements OnInit {
    firstPage = true;
    lastPage = false;
    presenters$ = new BehaviorSubject([
        {
            data: {
                id: 0,
                name: "Loading...",
                details: "Loading...",
                small_thumb: "",
                radio_shows: []
            },
            currentPage: 1,
            itemsPerPage: 0,
            totalItems: 0
        }
    ]);

    constructor(@Inject('api') private api,
                private colorService: ColorService,
                private http: Http,
                private route: ActivatedRoute,
                private router: Router) {
        route.params
            .map((p: any) => p.page)
            .switchMap(page => http.get(api + '/presenters?page=' + page))
            .map(res => res.json())
            .subscribe(this.presenters$);
    }
}

Обновление 1

Может ли что-то подобное работать?

console.log(x); кажется, возвращает мне правильные данные, но теперь ни один из моих (presenters$ | async)?.data все работает.

        .subscribe(
            function (x) {
                console.log(x);
                this.presenters$ = x;
            },
            null,
            function () {
                console.log("set the values here");
            }
        );

Обновление 2

Вышеуказанные разрывы, потому что this относится к вызову функции (дух!), но я получаю ошибки при попытке использовать жирную стрелку, кто-нибудь знает, что я здесь делаю неправильно?

.subscribe(
    x => this.presenters$ = x,
    null,
    function () {
        console.log("set the values here");
   }
);

Выше не бросает и ошибка, но все же async не работает.

Ниже выдается эта ошибка: "Ошибка: InvalidPipeArgument:" [объект объекта] "для канала" AsyncPipe ""

.subscribe(res => {
    this.presenters$ = res;
    // Any other lines here.
});

По ссылке ниже, похоже, мне просто нужно удалить асинхронную трубу, позже сделаю снимок. Angular 4: InvalidPipeArgument: '[объект объекта]' для канала 'AsyncPipe'

Обновление 3

Удаляя асинхронный канал из вызова данных в шаблоне (presenters$ | async)?.data" Я преодолел ошибку в последнем обновлении и смог получить функциональность после работы в среде разработчиков.

// component.html change
(presenters$)?.data

// latest subscribe that I have working, sort of
.subscribe(res => {
    this.presenters$ = res
    // got extras lines of code working here
});

Проблема сейчас в том, что не будет компилироваться для производства. Когда я пытаюсь скомпилировать, я получаю эту ошибку:

ОШИБКА в ng:///var/www/html/io->radio/src/app/ Presenters/views/ Presenters.component.html (2,1): Свойство>'data' не существует для типа 'BehaviorSubject< {данные: {id: номер; >имя: строка; детали: строка; small_thumb: строка; radio_s... '.

Обновление 4

Я начинаю думать, что я здесь полный дурак, и что BehaviorSubject это не то, что я должен использовать. Все, что я пытаюсь сделать, это вызвать данные из моего API и сопоставить их с объектом, если кто-то может сказать мне, что я делаю неправильно, это было бы очень полезно.

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

Мой следующий шаг - опробовать очень разумное предложение от @DeborrahK и создать сервис для извлечения данных.

1 ответ

Хитрость заключается в том, чтобы добавить фигурные скобки вокруг нескольких строк кода. У меня есть пример ниже.

.subscribe(res => {
                this.presenters$ = res;
                // Any other lines here.
            });

Но вы можете рассмотреть что-то вроде этого:

ngOnInit(): void {
    this.route.params.subscribe(
       params => {
            const id = +params['id'];
            this.getMovie(id);
            // I could have more lines of code here.
        }
    );
}

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

getMovie(id: number): void {
    this.movieService.getMovie(id)
        .subscribe(
              movie => {
                this.onMovieRetrieved(movie);
                // I could have more lines of code here
              },
              error => {
                 this.errorMessage = <any>error;
                 // I could have more lines of code here
              }
         );
}

Этот код вызывает сервис для извлечения данных. subscribe() это здесь. Http.get находится внутри сервиса.

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

У меня есть полный пример здесь: https://github.com/DeborahK/MovieHunter

Другие вопросы по тегам