首页 文章

Angular2 - OnInit:从Service'subscribe函数返回的值未分配给Component字段/ s

提问于
浏览
6

我正在尝试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()调用完成后,订阅函数返回的数据没有被传递/分配给我的Component属性'users' . 我知道数据是从服务方法调用返回到组件的,因为我能够在userService() . getUsers方法中记录数据 . 奇怪的是,我的ngOnInit上的console.log调用首先在我的开发控制台上打印在我的getUsers方法中的console.logs之前,尽管我首先调用了getUsers:

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

Dev控制台截图:

1 回答

  • 7

    这是因为 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() 而不是订阅,因此我们可以稍后订阅,以便能够在响应到达时执行代码 .

    然后在 ngOnInit() 中我们使用 subscribe()subscribe() 是必要的,否则将永远不会执行 http.get() )并传递我们想要在响应到达时执行的代码 .

    我还将 function () 更改为 () => . 这样 this 在以下代码块 () => { ... } 内部工作,否则不会 .

    别忘了添加

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

    否则这些操作员将无法识别 .

相关问题