【问题标题】:saving new property overwrites firebase object保存新属性会覆盖 firebase 对象
【发布时间】:2015-07-02 07:40:36
【问题描述】:

我正在使用 Firebase 和 Angular 进行测验。在测验结束时,我想使用以下代码将新属性保存到用户对象:

function saveTopscore() {
    var ref = new Firebase(CONSTANTS.FIREBASE_URL + 'users/' + User.user.$id + '/');
    var userObject = $firebaseObject(ref);
    userObject.topscore = User.totalCorrect;
    userObject.$save().then(function(ref) {
        console.log("worked");
    }, function(error) {
        console.log(error);
    });
}

它可以工作,但它也会覆盖用户对象的所有属性。因此,该对象用于保存名称、用户名、电子邮件、密码等,但是当我推送最高分时,它成为该对象的唯一属性。为什么?

【问题讨论】:

    标签: angularjs firebase


    【解决方案1】:

    你为什么在这里使用$firebaseObject?这仅在您将其三向绑定到 Angular 视图时才有用。如果您使用的是常规 JavaScript 代码,请坚持使用 Firebase 的常规 JavaScript SDK。

    在这种情况下,只需这样做:

    ref.update({ topscore: User.totalCorrect });
    

    【讨论】:

    • 感谢工作!我这样做是因为它在 api 文档中这么说。但这要容易得多。
    • 如果您不打算同步数据以在视图或服务中使用,我相当肯定 API 文档不会说使用 $bindTo 或任何 AngularFire 绑定。 (提示:我写的)
    【解决方案2】:

    正如@Frank 所说,使用 JavaScript SDK。

    我想澄清原始上下文(使用$firebaseObject),以防其他人将来提及此问题。

    • 之所以会出现最初的症状,是因为您正在设置对象的单个参数并在对象(及其已存在的子对象)完全下载之前保存它。
    • 因此,当您调用 .$save() 时,userObject 将(很可能)只设置其 topscore 参数,并且调用 .$save() 将有效地删除所有其他预先存在的子节点Firebase 参考。

    您可以使用.$loaded() 等到对象完全下载后再修改和/或更新它来避免这种情况...

    编辑:但是,正如Intro to AngularFire 指南所述,

    $loaded() 方法应谨慎使用,因为它仅在初始加载后调用一次。将它用于除调试之外的任何事情通常都是一种糟糕的做法。

    如果您忽略此警告并使用$loaded(),则该实现可能如下所示:

    注意 - 反模式:这不是推荐的做法。

    var ref = new Firebase(fbUrl + '/users/' + User.user.$id + '/');
    var userObject = $firebaseObject(ref);
    // wait until userObject has been downloaded, then modify & save it.
    userObject.$loaded().then(function(){
      userObject.topscore = User.totalCorrect;
      userObject.$save().then(function(ref) {
          console.log("Saved");
      }, function(error) {
          console.log(error);
      });
    });
    

    正如弗兰克在 cmets 中对这个答案所说的那样,

    “如果你在$firebaseObject(或$firebaseArray)之后直接使用$loaded(),你可能做错了什么。”

    【讨论】:

    • 嘿思南。你的方法也有效。但是我已经开始使用一个规则:“如果你在$firebaseObject(或$firebaseArray)之后直接使用$loaded(),你可能做错了什么”。我们看到$loaded() 的使用太多了,我将展示为什么人们在我能做到的地方不需要它。 ;-) 仍然......你的解决方案也确实有效。
    • 嗨弗兰克。这是一个伟大的观点,这是一个伟大的规则!感谢您的澄清。我希望解释如何下载数据的过程。我现在在Intro to AngularFire 中看到,将$loaded() 用于除调试以外的其他事情被认为是不好的做法。如果$loaded() 被过度使用,有没有解决这个问题的计划?我认为有一个功能性反模式列表作为参考会很棒。
    • 您找到的新文档是我们试图更加明确的一种方式。但这仍然很棘手。我们经常告诉人们简单地将$firebaseObject 绑定到他们视图中的元素。它将用更少的代码完成他们尝试做的事情(调试/检索什么数据),这就是 AngularFire 的全部意义所在。
    • 伟大的讨论和伟大的想法。 Sinan,如果您遇到任何您认为可能是好的用法或反模式的内容,请通过电子邮件发送,我们将添加到文档中。
    • @SinanBolel 我认为为什么人们一直犯上述错误并且可能会选择 $loaded 而不是简单地使用 SDK 更新是 SDK 更新不返回承诺......但 firebaseObject 会。所以在服务中使用它我们不需要费心去创建一个 $q 并将 promise 返回给控制器。所以我认为 $loaded 方法在 Angular 环境中更直接(纠正我是我错了)。但是弗兰克关于“你可能做错了什么”的说法确实让我害怕现在这样做......