簡體   English   中英

Angular2 - OnInit:從服務的訂閱函數返回的值沒有分配給組件字段

[英]Angular2 - OnInit : Values returned from Service' subscribe function does not get assigned to Component field/s

我正在嘗試 Angular2 並一直在關注他們的教程。

我目前有一個從 json 服務器獲取數據的服務:

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';

import { Observable } from 'rxjs/Observable';

import { User } from './user';

@Injectable()
export class UserService {
  constructor(private http: Http) {}

  private usersUrl = 'http://localhost:3000/users';

  getUsers(): Observable<User[]> {
    return this.http.get(this.usersUrl) //the request won't go out until something subscribes to the observable
                    .map(this.extractData)
                    .catch(this.handleError); // pass an error message back to the component for presentation to the user but only if we can say something the user can understand and act upon
  }

  private extractData(response: Response) {
    if (response.status < 200 || response.status >= 300) {
       throw new Error('Bad response status: ' + response.status);
    }
    let body = response.json(); // parse JSON string into JavaScript objects

    return body.data || { };
  }

  private handleError (error: any) {
    // In a real world app, we might send the error to remote logging infrastructure before returning/sending the error
   let errMsg = error.message || 'Server error'; // transform the error into a user-friendly message

   return Observable.throw(errMsg); // returns the message in a new, failed observable
  }

}

還有我的組件:

import { Component, OnInit } from '@angular/core';

import { User } from '../common/user/user';
import { UserService } from '../common/user/user.service';

@Component({
  selector: 'app-nav',
  templateUrl: '/app/nav/nav.component.html',
  styleUrls: ['/app/nav/nav.component.css']
})
export class NavComponent implements OnInit {
  errorMsg: string;
  users: User[];

  constructor(private userService: UserService) { }

  getUsers() {
    this.userService
    .getUsers()
    .subscribe(
      function(users) {
        console.log('users ' + users);
        this.users = users;
        console.log('this.users ' + this.users);
      }, function(error) {
        console.log('error ' + error);
      });
    // users => this.users = users,
    // error => this.errorMsg = <any>error);
  }

  ngOnInit() {
    this.getUsers();
    console.log('ngOnit after getUsers() ' + this.users);
  }
}

我的問題是,在 getUsers() 調用完成后,從訂閱函數返回的數據沒有傳遞/分配給我的組件屬性“用戶”。 我確實知道數據從服務方法調用返回到組件,因為我能夠在 userService().getUsers 方法中記錄數據。 奇怪的是,我的 ngOnInit 上的 console.log 調用首先在我的 getUsers 方法中的 console.logs 之前打印在我的開發控制台上,盡管我首先調用了 getUsers:

  ngOnInit() {
    this.getUsers();
    console.log('ngOnit after getUsers() ' + this.users);
  }

開發控制台截圖:

這是因為this.userService.getUsers().subscribe(...) this.getUsers()this.userService.getUsers().subscribe(...)只安排調用向服務器發出請求。 最終當來自服務器的響應到達時( console.log('ngOnit after getUsers() ' + this.users);在調用服務器之前已經執行了)然后你傳遞給subscribe()的函數被執行.

這應該做你想做的:

  getUsers() {
    return this.userService
    .getUsers()
    .map(
      (users) => {
        console.log('users ' + users);
        this.users = users;
        console.log('this.users ' + this.users);
      })
     .catch((error) => {
        console.log('error ' + error);
        throw error;
      });
    // users => this.users = users,
    // error => this.errorMsg = <any>error);
  }

  ngOnInit() {
    this.getUsers().subscribe(_ => {;
      console.log('ngOnit after getUsers() ' + this.users);
    });
  }

getUsers()我使用map()而不是 subscribe,因此我們可以稍后訂閱,以便能夠在響應到達時執行代碼。

然后在ngOnInit()我們使用subscribe()subscribe()是必要的,否則http.get()將永遠不會被執行)並在響應到達時傳遞我們想要執行的代碼。

我還將function ()更改為() => 這樣this可以在下面的代碼塊() => { ... } ,否則就不會。

不要忘記添加

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

否則這些運算符將不會被識別。

對我來說,這就像魔術一樣,我需要從 api 獲取數據來初始化數據表組件

1- 在您的 http 服務上創建正常的 get 請求,如下所示:

  public get(url: string):Observable<any> {
    return this.http.get<any>( url );
   }

2- 在您的組件上:

constructor(private HttpSvc: HttpService) {}

  ngOnInit() {
    this.render();
  }    
render() {
        let options = this.options || {};
          this.HttpSvc.Get('your api url').subscribe(data => {
            this.Tableset = data;
            options = {
              data: this.Tableset.data,
              columns: this.Tableset.columns,
              dom: 'Bfrtip',
              buttons: this.Tableset.buttons,
              autoWidth: false,
              pageLength: 2,
              retrieve: true,
              responsive: true
            };
          }, err => {console.log(err); },
          () => {
            this.renderDetails(options); //<-- can call any other method after call end
          });
    }

這里是完整的示例鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM