【问题标题】:AngularFire2 firestore take(1) on doc valueChangesAngularFire2 firestore take(1) on doc valueChanges
【发布时间】:2018-03-21 03:33:45
【问题描述】:

使用 AngularFire2 我尝试从单个 Firestore 文档中获取数据。 有效的是

this.addressRef = afs.doc<Address>('addresses/key')
this.addressRef.valueChanges().subscribe(val => {......}

我只想运行一次订阅代码。通常我使用 take(1) 来实现这一点(与 Firebase DB 一起使用)。 但是这段代码

this.addressRef.valueChanges().take(1).subscribe(val => {......}

给出错误:TypeError:this.addressRef.valueChanges(...).take 不是函数。

VS Code 正在列出执行操作。这是 AngularFire2 中的错误,我做错了还是有其他(更好的)方法可以在获取数据后停止订阅?我也尝试过 topromise,但这也失败了。

【问题讨论】:

    标签: angular firebase angularfire google-cloud-firestore


    【解决方案1】:

    更新

    因为这个答案受到了很多关注,所以我提供了一个更新的答案。通常,在使用可观察对象进行编程时,您应该尝试进行反应式思考。有一些很棒的教程,但是this one is 很好。

    新解决方案

    user$ = this.afDs.doc<User>('users/NaGjauNy3vYOzp759xsc')
      .valueChanges().pipe(
        take(1) // Here you can limit to only emit once, using the take operator
      )
    

    在你的模板中,你订阅了你的 observable。

    {{(user$ | async).name}}
    

    上下文

    这种解决问题的方法有很多好处:

    • 如果您不想转换数据,则只需输入地图运算符
    • 您可以使用 rxjs 过滤器操作符过滤事件
    • 根据 user$ 流创建其他流
    • 易于调试,因为其他开发人员可以以更透明的方式查看您应用中的数据流

    例如(创建另一个流,仅在用户是管理员时发出,并创建一个新标题):

    adminTitle$ = this.user$.pipe(
      filter(user => user.title === 'admin'),
      map(user => `${user.name} (admin)`)
    )
    

    旧答案

    您可以通过执行以下操作来实现此目的:

    this.userDoc = afDs.doc<User>('users/NaGjauNy3vYOzp759xsc');
    this.userDoc.valueChanges()
      .pipe(take(1))
      .subscribe(v => {
        this.user = v;
      });
    

    【讨论】:

    • 好的,起初我在您的答案中没有看到太多新内容,因为我已经使用了相同的代码,但是 take() 在我的设置中不起作用。但是在研究了你的 stackblitz 之后,我发现我的导入是不同的。我猜它们是由 VC 自动生成的。我将“rxjs/operator/take”作为导入路径。如您的示例中所示,将其更改为“rxjs/add/operator/take”,现在 take() 可以工作了。所以感谢您提供完整的代码。我会进一步研究这些不同的路径。
    • 现在每次您需要例如 user.uid 来编写其他代码时,您需要在订阅中执行此操作吗?这使得代码看起来很奇怪和嵌套。你不能从数据库中获取当前用户 uid 并在你的组件中使用它(所以不是 html)而不订阅?
    • @Ruben 你还需要这方面的帮助吗?简短的回答是肯定的——你必须订阅。但是你不需要多次调用它:)
    • @DauleDK 谢谢,我明白了,但我的代码看起来很奇怪,我的应用程序中几乎每个页面都需要当前登录的用户 UID,但我每次都需要订阅(一次),如果 UID 是一个全局变量,我可以在不使用订阅的情况下在任何地方访问它会更容易。我的大部分其他代码都应该在我获得 UID 后运行,所以这有点烦人
    • 嗨@Ruben - 如果你问我,为了避免这种情况,你有两个选择。您可以将 UID 存储在浏览器存储中。在 Angular 中,您可以简单地执行 localStorage.setItem('uid', &lt;uid&gt;),然后在需要时执行 localStorage.getItem(uid)。您还可以创建一个服务,注入您的应用程序模块。请记住在用户注销时清除 uid :)
    猜你喜欢
    • 2020-06-19
    • 2019-12-04
    • 2018-05-27
    • 1970-01-01
    • 2018-11-03
    • 1970-01-01
    • 2018-12-29
    • 2018-06-29
    • 1970-01-01
    相关资源
    最近更新 更多