HttpClient空成员变量虽然已分配

时间:2017-10-05 20:46:48

标签: angular

在Angular4中,对端点发出请求,并从中返回Post的数组。标题是正确的。在'next' subscribe()中的data内部被正确分配,console.log显示它。但this.posts为空或未定义,正如您在帖子console.log中看到的那样。

有什么问题,如何解决?

我正在考虑在初始化实例后实现的承诺。怎么会这样? 或者它超越if语句并在请求发出之前返回一个未定义的值。

我怎么能不这样做?

import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';

@Injectable()
export class PostService {

  private serviceUrl = 'http://localhost:8080/api/posts';
  private posts: Post[];

  constructor(private http: HttpClient) {
  }

  // get all posts or all posts by channel
  list(channel?: string|undefined): Post[] {
    if (channel) {
      this.http.get<Array<Post>>(this.serviceUrl + '?channel=' + channel).subscribe(
        data => {
          console.log('data', data);
          this.posts = data;
          console.log('posts1', this.posts);
          return data;
        },
        err => {
          console.log(err);
        }
      );
    } else {
      this.http.get<Array<Post>>(this.serviceUrl).subscribe(
        data => {
          console.log('data', data);
          this.posts = data;
          console.log('posts1', this.posts);
        },
        err => {
          console.log(err);
        }
      );
    }

    console.log('posts2', this.posts);
    return this.posts;
  }

  // get one post by Id
  get(id: string): Post {
    let post: Post = new Post();
    this.http.get<Post>(this.serviceUrl + '/' + id).subscribe(
      data => {
        post = data;
      }
    );
    return post;
  }

  create(post: Post): void {
    this.http.post<any>(this.serviceUrl, post).subscribe();
  }

  update(post: Post): Post {
    let r: Post = new Post();
    this.http.put<Post>(this.serviceUrl, post).subscribe(
      data => {
        r = data;
      },
      err => {
        console.log(err);
      }
    );
    return r;
  }

  remove(id: string): void {
    this.http.delete(this.serviceUrl + '/' + id).subscribe();
  }

}

export class Post {
  id: string;
  authorId: string;
  title: string;
  slug: string;
  body: string;
  channels: string[];
  createdAt: string;
}

结果

post.service.ts:40 posts2 undefined
post.service.ts:30 data (2) [{…}, {…}]
post.service.ts:32 posts1 (2) [{…}, {…}]

1 个答案:

答案 0 :(得分:1)

此:

console.log('posts2', this.posts);

返回undefined,因为它是在返回数据之前执行的。

Http请求是异步的,因此发出请求并且AT SOME LATER POINT IN TIME,返回值并执行订阅回调。

这是一张带有显示执行顺序的数字的图片。

enter image description here

使用服务

由于其工作方式,您通常会看到服务执行请求并返回observable。 CALLER代码执行订阅,然后可以知道何时返回值。

我的服务电话如下:

getMovies(): Observable<IMovie[]> {
    return this.http.get<IMovie[]>(this.moviesUrl)
                    .do(data => console.log(JSON.stringify(data)))
                    .catch(this.handleError);
}

我的组件代码如下所示:

getMovies(): void {
    this.movieService.getMovies()
        .subscribe(
            (movies: IMovie[]) => {
                this.movies = movies;
            },
            (error: any) => this.errorMessage = <any>error);
}

使用解析器

另一个选择是使用解析器。如果您构建了一个解析器,则可以确保在显示路径之前检索数据。

以下是解析器的示例:

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';

import { Observable } from 'rxjs/Observable';

import { IMovie } from './movie';
import { MovieService } from './movie.service';

@Injectable()
export class MovieResolver implements Resolve<IMovie> {

    constructor(private movieService: MovieService) { }

    resolve(route: ActivatedRouteSnapshot,
            state: RouterStateSnapshot): Observable<IMovie> {
        const id = route.paramMap.get('id');
        return this.movieService.getMovie(+id);
    }
}

当绑定到路径时,此代码将在显示路由组件的模板之前执行(并将检索数据)。这可以让你达到你想要的。