在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) [{…}, {…}]
答案 0 :(得分:1)
此:
console.log('posts2', this.posts);
返回undefined,因为它是在返回数据之前执行的。
Http请求是异步的,因此发出请求并且AT SOME LATER POINT IN TIME,返回值并执行订阅回调。
这是一张带有显示执行顺序的数字的图片。
使用服务
由于其工作方式,您通常会看到服务执行请求并返回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);
}
}
当绑定到路径时,此代码将在显示路由组件的模板之前执行(并将检索数据)。这可以让你达到你想要的。