如何在Angular 4中渲染视图之前确保数据可用

时间:2017-08-19 07:07:26

标签: angular

我有两个组件,博客和帖子。帖子位于Blog组件中。仅在第一次使用服务时,数据不会显示在帖子视图下。如果我来回两个不同的视图,那么数据会出现。那么,如何在未加载数据之前停止渲染视图呢?

我正在尝试从以下API(https://jsonplaceholder.typicode.com/posts)获取数据。如果我直接在组件中使用HTTP get,那么提取工作正常,

this.http.get('https://jsonplaceholder.typicode.com/posts')
    .map((response) => {
        return response.json();
    })
    .subscribe((data) => {
        // console.log(data);
        this.posts =  data;
    });

但是当我将代码移动到服务时会出现问题。

我有一个博客服务,

import { Injectable } from '@angular/core';
import {Http} from '@angular/http';
import 'rxjs/add/operator/map';

@Injectable()
export class BlogService {
  posts = [];

  constructor(private http: Http) { }

  fetchAllPosts() {
    this.http.get('https://jsonplaceholder.typicode.com/posts')
        .map((response) => {
          return response.json();
        })
        .subscribe((data) => {
          // console.log(data);
          this.posts = data;
        });
  }

  getAllPosts() {
    // console.log(this.posts);
    return this.posts.slice();
  }

}

我正在从博客组件

调用fetchAllPosts()
ngOnInit() {
  this.blogService.fetchAllPosts();
}

然后在postsComponent中,我正在调用getAllPosts()。

ngOnInit() {
    this.posts = this.blogService.getAllPosts();
    console.log(this.posts);
}

以下是博客组件

<div class="container">
    <app-posts></app-posts>
</div>

3 个答案:

答案 0 :(得分:1)

注意:您应该避免在服务中使用.subscribe()

export class BlogService {
  posts = [];

  constructor(private http: Http) { }

  fetchAllPosts() {
    this.http.get('https://jsonplaceholder.typicode.com/posts')
        .map((response) => {
          return response.json();
        })
  }

  getAllPosts() {
    // console.log(this.posts);
    return this.posts.slice();                   // I don;t know why are you using .slice() here. It should be return this.posts();
  }
}

PostComponent

posts:[];                                       // I believe you use this posts object in PostComponent template

ngAfterViewInit() {
    this.posts = this.blogService.getAllPosts();
    console.log(this.posts);
}

// if above block doesn't work for you , you can use setTimeOut()



ngAfterViewInit() {
        setTimeout(()=>{
           this.posts = this.blogService.getAllPosts();
           console.log(this.posts);
        },500)

    }

BlogComponent

constructor(private bgService:BlogService){       // added service
                  blogService
                  .fetchAllPosts()
                  .subscribe((data) => {
                      // console.log(data);
                      this.bgService.posts = data; // look at here, this will update posts object 
                   });

}

答案 1 :(得分:0)

使用*ngIf,如下所示

<div class="container">
     <div *ngIf="posts?.length > 0">
          <app-posts></app-posts>
    </div>
</div>

答案 2 :(得分:0)

所以......还有一个选择。这允许服务保留数据并与应用程序的其他部分共享:

@Injectable()
export class BlogService {
  private _posts()  = [];

  get posts() {
    return _posts;
  }

  constructor(private http: Http) { }

  fetchAllPosts() {
    this.http.get('https://jsonplaceholder.typicode.com/posts')
        .map((response) => {
          return response.json();
        })
        .subscribe((data) => {
          // console.log(data);
          this.posts = data;
        });
  }
}

通过使用getter而不是方法(例如getAllPosts),组​​件可以绑定到此属性,数据一到达就会被绑定,并由http get设置。

PostComponent 是:

   get posts() {
      return this.blogService.posts;
   }

取代您拥有的ngOnInit代码。

这样你就可以绑定到PostComponent的html中的任何位置。该值最初是未定义的,因此您需要使用@aravid显示的技术并确保HTML可以处理未定义的。

当数据从服务器到达时,更改检测将确保在绑定属性中更新该值。

我有一个在这里演示此技术的plunker:https://plnkr.co/edit/BZT2oe8YmRS717lN0nPh?p=preview