【问题标题】:Angular 2 not updating when array is updated更新数组时Angular 2不更新
【发布时间】:2016-01-04 19:05:26
【问题描述】:

我有一个通过 firebase 获取一些对象的服务。然后它会填充一个数组,然后应该提示 angular 使用 *ngFor 语句更新 DOM,但它不起作用。代码如下:

TeachersService

    import {Injectable} from 'angular2/core';
import {Teacher} from './teacher.ts';

@Injectable()
export class TeachersService {

  private firebaseURL: string;
  private teachersRef: Firebase;

  constructor() {
    this.firebaseURL = "https://xyz.firebaseio.com/teachers";
    this.teachersRef = new Firebase(this.firebaseURL);
  }

  getTeachers() {

    this.teachersRef.on("value", function(snapshot) {

      var tempArr = new Array(snapshot.numChildren());
      // this.teachers = snapshot.val();
      snapshot.forEach(function(data) {
        var teacher = {
          name: data.key(),
          position: data.val().stilling
        }
        tempArr.push(teacher);
      });
      // this.teachers = tempArr;
      console.log(tempArr);
      return Promise.resolve(tempArr);
    });

    return Promise.resolve([]);
  }
}

还有Teachers

import {Component, AfterViewInit, OnInit, View} from 'angular2/core';

import {NgFor} from 'angular2/common';
import {Router} from 'angular2/router';

import {TeachersService} from '../../services/teachers.service';

@Component({
  selector: 'teachers',
  templateUrl: './components/teachers/teachers.html',
  providers: [TeachersService]
})


export class TeachersCmp implements AfterViewInit, OnInit {

  private firebaseURL: string;
  private teachersRef: Firebase;
  public teachers: Array<any>;
  constructor(
    private _router: Router,
    private _teachersService: TeachersService
  ) {}

  ngOnInit() {
    this.populateTeachersArr();
  }

  populateTeachersArr() {
    this._teachersService.getTeachers().then(teachers => this.teachers = teachers);
  }

}

Teachers.html

<ul>
<li *ngFor="#teacher of teachers">
        <strong>{{teacher.name}}</strong>: {{teacher.position}}
      </li>

我怀疑这与变更检测有关(或者至少我对它的理解)。但是不知道怎么提示ng2检测数组更新。如果我创建了一个静态数组,例如:[1,2,3,4],*ngFor 语句可以正常工作并像在 DOM 中一样显示它。

【问题讨论】:

  • 它肯定是@GünterZöchbauer。但是有点厚,你能提供一个如何实现的例子吗?
  • 我认为问题出在您在 getTeachers 函数中使用承诺的方式(请参阅我的回答),并且与变更检测无关......

标签: angular


【解决方案1】:

我发现你使用 Promise 的方式有点奇怪。这应该是你的问题的原因。事实上,您返回一个用空数组解析的承诺。该数组直接在另一端的then 方法中使用。当收到value 事件时,您会在回调中返回另一个从未使用过的承诺。

我认为您应该返回一个承诺并在value 事件的回调中收到值时解决它。

这是我将在 getTeachers 方法中提出的重构来解决您的问题:

getTeachers() {
  return new Promise((resolve, reject) => {
    this.teachersRef.on("value", function(snapshot) {
      var tempArr = new Array(snapshot.numChildren());
      snapshot.forEach(function(data) {
        var teacher = {
          name: data.key(),
          position: data.val().stilling
        }
        tempArr.push(teacher);
      });
      resolve(tempArr);
    });
  });
}

编辑

在 Firebase 上对您的代码进行了一些测试后,它发现了问题所在。事实上,在这里使用 Promise 是不可能的,因为它们只被调用一次。我的意思是在then 方法中指定的回调将只为第一个value 事件调用。这是 Promise 的一个缺点。

要克服这个限制,你需要使用 observables。这是getTeachers方法的重构版本:

import {Injectable} from 'angular2/core';
(...)
import {Observable} from 'rxjs/Rx';

@Injectable()
export class TeachersService {
  (...)
  getTeachers() {
    return new Observable(observer => {
      this.teachersRef.on("value", snapshot => {
        var tempArr = [];
        snapshot.forEach(function(data) {
          var teacher = {
            name: data.key(),
            position: data.val().stilling
          }
          tempArr.push(teacher);
        });
        observer.next(tempArr);
      }
    });
  }

在组件中,您可以像这样调用getTeachers 方法:

@Component({
  (...)
  template: `
    (...)
    <ul>
      <li *ngFor="#teacher of teachers">
        <strong>{{teacher.name}}</strong>
      </li>
    </ul>
  `,
  providers: [ TeachersService ]
})
export class AppComponent {
  (...)

  ngOnInit() {
    this.populateTeachersArr();
  }

  populateTeachersArr() {
    this._teachersService.getTeachers().subscribe(teachers =>
      this.teachers = teachers;
    );
  }
}

或者通过利用async 管道(它将直接管理可观察对象)更进一步:

@Component({
  (...)
  template: `
    (...)
    <ul>
      <li *ngFor="#teacher of (teachers | async)">
        <strong>{{teacher.name}}</strong>
      </li>
    </ul>
  `,
  providers: [ TeachersService ]
})
export class AppComponent {
  (...)

  ngOnInit() {
    this.populateTeachersArr();
  }

  populateTeachersArr() {
    this.teachers = this._teachersService.getTeachers();
  }
}

希望对你有帮助 蒂埃里

【讨论】:

  • 您好蒂埃里,感谢您的回复。恐怕这会产生相同的结果,即没有显示数据。我认为 Gunther 的提议可能与此处描述的同一问题有关:stackoverflow.com/questions/34592857/… 是正确的,我只是不知道如何实施。
  • 明天我会尝试重现您的 Firebase 问题...我会及时通知您 ;-)
  • 我认为适合我的解决方案 ;-) 这是因为承诺的限制。您应该改用 observables。我用工作代码更新了我的答案。随意告诉它是否可以解决您的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-04
  • 2017-06-08
  • 2016-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多