Визуализация наблюдаемых в Angular 5

Я пытаюсь отобразить Observable в Angular. Я делаю запрос к API, чтобы получить некоторые данные, но когда я пытаюсь их отобразить, в браузере ничего не появляется.

Это сервис, который я использую для получения данных об 1 пользователе:

export class UserService {

  public _url: string = "https://url/rest/user/";

  constructor(private http: HttpClient) { }

  getUser(id): Observable<IUser>{
    return this.http.get<IUser>(this._url + id)
                  .catch(this.errorHandler);
  }

  errorHandler(error: HttpErrorResponse){
    return Observable.throw(error.message);
  }
}

Это пользовательский компонент:

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  providers: [ UserService ],
  styleUrls: ['./user.component.css']
})

export class UserComponent implements OnInit {

  public userId;    
  public errorMsg;
  user: IUser;

  constructor(private route: ActivatedRoute, private _userService: 
  UserService) { }

  ngOnInit() {

    let id = parseInt(this.route.snapshot.paramMap.get('id'));
    this.userId = id;

    this._userService.getUser(this.userId)
          .subscribe(data => this.user = data,
                 error => this.errorMsg = error);

  }

}

И представление HTML, которое я использую для отображения пользователя, выглядит следующим образом:

<div>
  <h2>{{user?.firstName}} {{user?.lastName}}</h2>
    <dl>
     <dt>Age:</dt>
     <dd>{{user?.age}}</dd>

     <dt>ID:</dt>
     <dd>{{user?.id}}</dd>

     <dt>Email:</dt>
     <dd>{{user?.email}}</dd>
   </dl>
</div>

В этом примере у меня нет ошибок, но все пользовательские поля пусты, ничего не отображается. Я пытался использовать это:

<div *ngIf="user | async; let user; else loading">
<ng-template #loading>Loading User Data...</ng-template>

Но это не работает, консоль показывает:

Error: InvalidPipeArgument: '[object Object]' for pipe 'AsyncPipe' ...

Я делаю тот же процесс в другом компоненте, где я использую массив пользователей, таких как IUser[], на этот раз я показываю данные с помощью ngfor, и все правильно, данные отображаются в браузере, как и ожидалось. Я делаю это так же, как я объяснил выше, но используя ngif или user?.id и без массивов.


person Samuel    schedule 08.02.2018    source источник
comment
что вы получите, если добавите console.log(data) в свой метод подписки? Или лучше, если вы установите точку останова там   -  person David    schedule 09.02.2018
comment
Привет, я уже проверил данные с помощью console.log, и данные верны, я получаю контент, который хочу показать. И внутри метода подписки данные также правильно назначаются моему пользователю.   -  person Samuel    schedule 09.02.2018
comment
Не могли бы вы опубликовать минимальную версию вашей проблемы на stackblitz? stackblitz.com   -  person David    schedule 09.02.2018
comment
Конечно, я думаю, вот оно.   -  person Samuel    schedule 09.02.2018
comment
Смотрите мой ответ ниже   -  person David    schedule 09.02.2018


Ответы (3)


API возвращает список пользователей, а не одного пользователя (даже если вы указали ответ как IUser)

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

getUser(id): Observable<IUser> {

    return this.http.get<IUser>(this._url + id).map(resp => resp[0])
                    .catch(this.errorHandler);
}

См. измененный код: https://angular-uqsks5.stackblitz.io

person David    schedule 09.02.2018

Что касается последней ошибки, канал async работает только с наблюдаемыми. Поэтому вместо того, чтобы сохранять данные в пользовательской переменной и затем передавать их в асинхронный канал, попробуйте сохранить сам наблюдаемый объект: const user$ = this._userService.getUser(this.userId), а затем передать его в канал async: {{ user$ | async }}.

Затем вы можете получить доступ к свойствам следующим образом: {{ (user$ | async).age }} и так далее.

Для вашей первоначальной ошибки это может быть просто проблема с запросом. Вы можете попробовать вывести значение data на консоль в своей подписке для устранения неполадок. Возможно, вам нужно data.response или что-то в этом роде. (Одним из способов проверить это является использование наблюдаемого подхода, о котором я упоминал выше, и выполнение {{ user$ | async | json }} в вашем шаблоне, чтобы увидеть, что вызов userService.get дает вам.

Обратите внимание, что хотя вы можете настроить подписку вручную, вам нужно будет самостоятельно очистить подписку. Труба async — это то, что нужно для такого типа вещей.

Для получения дополнительной информации об этом см. здесь: https://angular.io/api/common/AsyncPipe

person vince    schedule 08.02.2018
comment
Я сделал то, что вы упомянули, но не работает, в браузере ничего не появляется, как будто это был пустой ответ (и, конечно, это не так). - person Samuel; 08.02.2018

Во-первых, вам нужно импортировать ответ из @angular/http в свой сервис.

import { Http, Headers, Response } from "@angular/http";

И карта из rx/js:

import { map } from 'rxjs/operators';

Затем в вашем сервисе попробуйте следующее:

return this.http.get(this._url + id).pipe(
  map((resp:Response) => resp.json())
)

Это должно сопоставить ваш ответ с JSON. Подписка на observable должна работать так, как она есть сейчас в вашем компоненте.

person thisisdamon    schedule 08.02.2018
comment
Невозможно использовать .json(). Он говорит, что свойство «json» не существует для моего интерфейса IUser - person Samuel; 08.02.2018
comment
Плохо... вам, вероятно, следует использовать свой интерфейс для отображаемых данных, которые возвращаются (в компоненте). Вы уже объявляете this.user как IUser, поэтому удаление ‹IUser› из вызова API может сработать. Я обновлю свой ответ... - person thisisdamon; 09.02.2018
comment
И как я мог получить данные тогда в компоненте? не могли бы вы и мне сказать? Спасибо - person Samuel; 09.02.2018