【问题标题】:Angular service constructor raceAngular 服务构造函数竞赛
【发布时间】:2019-01-22 00:35:42
【问题描述】:

我有一个具有数据服务的 Angular 应用程序

...

@Injectable()
export class DataService {
  collectionEndpoint: string;
  counters: AngularFirestoreCollection<Counter>;

  constructor(private db: AngularFirestore, private authService: AuthService) {
    this.collectionEndpoint = "users/" + this.authService.userData.uid + "/counters";
    this.counters = db.collection<Counter>(this.collectionEndpoint, ref =>
      ref.orderBy("name")
  );

  getCounters() {
  return this.counters.snapshotChanges().pipe(
    map(actions =>
      actions.map(a => {
        const data = a.payload.doc.data() as Counter;
        const id = a.payload.doc.id;
        return { id, ...data };
      })
    )
  );
}

...

}

在其构造函数中有AuthServiceAuthService如下:

...

Injectable({
  providedIn: "root"
})
export class AuthService {
  userData: firebase.User;

  constructor(
    private angularFireAuth: AngularFireAuth
  ) {
    this.angularFireAuth.authState.subscribe(userData => {
      if (userData) {
        this.userData = userData;
      }
    });
  }

...

}

然后在组件中访问它

export class CounterDashboardComponent {
    counters: Observable<Counter[]>;

    constructor(private counterService: CounterService) {
      this.counters = this.counterService.getCounters();
    }

...

}

这是通过*ngFor="let counter of (counters | async)"在html中访问的

当在使用DataService 的路由上刷新页面(正确进入页面)时,它会在 authService 填充该属性之前尝试访问authService.userData.uid(构造函数的第一行)。

如何解决/避免这种情况?

提前谢谢。

【问题讨论】:

  • 将调用移出构造函数?
  • 通过调用,我猜你的意思是调用填充this.counters。此数据立即在组件 html 中使用,并且需要在构建时可用。
  • 将组件中的this.counters =... 移动到不同的生命周期钩子中。可能是 onInit。
  • 这会将问题从构造函数转移到getCounters(),因为它在未定义的this.counters 上调用snapshotChanges()。原谅来回,我仍然对如何解决基本问题感到困惑。

标签: angular typescript firebase-authentication


【解决方案1】:

目前由您的示例给出,没有理由创建新的 AuthService


@Injectable()
export class DataService {
  collectionEndpoint: string;
  counters: AngularFirestoreCollection<Counter>;

  constructor(private db: AngularFirestore) {
    angularFireAuth.authState.subscribe(userData => {
      this.collectionEndpoint = "users/" + userData.uid + "/counters";
      this.counters = db.collection<Counter>(this.collectionEndpoint, ref =>
        ref.orderBy("name"));
    })
  }
...

【讨论】:

  • 属性this.counters很快被html使用,然后this.counters属性在运行时未定义;
  • 然后更新您的 HTML 以处理它是异步调用的事实(因此需要订阅)。根据定义,它不会立即出现。
  • Angular 处理传递给 HTML 模板的数据,并在计数器数据更改时重新呈现 HTML。如果 counters 在 HTML 中未定义,则其原因不同。我强烈建议浏览 Angular 教程 angular.io/tutorial 它涵盖了大部分内容
  • 我已经更新了这个问题,它最终是如何在前端使用的。它正在异步访问 Observable。但是当getCounters() 访问this.counters 属性时,它还不存在。
【解决方案2】:

对我有用的解决方案是直接从组件(即 *ngFor="let counter of (counterService.counters | async))监听 DataService 中的 Observable(使用构造函数中的 Counters 初始化一个 observable)。

非常感谢提供帮助的人。

【讨论】:

    猜你喜欢
    • 2018-03-23
    • 2010-10-02
    • 1970-01-01
    • 1970-01-01
    • 2014-06-06
    • 2017-06-02
    • 2019-05-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多