服务器数据更改时 $loaded 无法正常工作

$loaded is not working properly when the server data is changed

我是 firebase 和 angularjs 的新手。对于我的销售应用程序,我想同时使用两者。因此,在我的应用程序中,我使用的是 AngularJS v1.5.8 + Firebase v3.3.0 + AngularFire 2.0。 2。我在 firebase db 中有 sales 和 users 对象,并且有一个业务逻辑,一个用户可以销售多个产品,但一个产品只能有一个所有者(用户)。

这是数据库中的 userssales 对象:

{
  "sales" : {
    "-KQlb5N6A9rclc5qcWGD" : {
      "price" : 8,
      "quantity" : {
        "count" : 12,
        "type" : "porsiyon"
      },
      "status" : "sale",
      "title" : "Patlicanli Borek",
      "user" : "-KQ52OJd-lwoDIWzfYFT"
    },
    "-KQlcScsq8cidk7Drs04" : {
      "price" : 12,
      "quantity" : {
        "count" : 10,
        "type" : "porsiyon"
      },
      "status" : "sale",
      "title" : "Deneme",
      "user" : "-KQ5-mZBt6MhYy401gGM"
    },
    "-KQzXHwOv2rC73scjV46" : {
      "price" : 12,
      "quantity" : {
        "count" : 11,
        "type" : "porsiyon"
      },
      "status" : "sale",
      "title" : "Pacanga",
      "user" : "-KQ5-mZBt6MhYy401gGM"
    },
    "-KSCBgpArtnKunUuEuVr" : {
      "price" : 15,
      "quantity" : {
        "count" : 15,
        "type" : "porsiyon"
      },
      "status" : "sale",
      "title" : "Iskembe",
      "user" : "-KQ52OJd-lwoDIWzfYFT"
    }
  },
  "users" : {
    "-KQ5-mZBt6MhYy401gGM" : {
      "address" : "Halkali kucukcekmece",
      "email" : "burak.kahraman@gmail.com",
      "name" : "Burak Hero",
      "nick" : "Burak'in Mutfagi"
    },
    "-KQ52OJd-lwoDIWzfYFT" : {
      "address" : "Izmir kaynaklar",
      "email" : "ayse@gmail.com",
      "name" : "Ayse Kahraman",
      "nick" : "Ayse'nin Mutfagi"
    }
  }
}

我想要做的是当我的应用程序打开时,它会显示所有销售额 以及相应的用户详细信息。 (就像 letgo 应用程序的主页一样)这意味着我应该在 sales 和 users 对象之间实现一个简单的连接。据我在整个互联网和 api 文档中搜索,没有办法在对 firebase 的单个调用中实现这种连接。 (如果我错了,请纠正我)所以我使用下面的方法在我的 SalesService 中使用 $loaded 函数来实现连接。

angular.
  module('core.sales')
  .service('SalesService', function ($firebaseArray, $firebaseObject, UsersService) {
this.getAllSalesJoin = function () {
      var sales;
      var refSales = firebase.database().ref('sales');
      sales = $firebaseObject(refSales);
      sales.$loaded()
        .then(function () {
          angular.forEach(sales, function (sale) {
            var saleUser = UsersService.getUserDetail(sale.user);
            saleUser.$loaded()
              .then(function () {
                sale.user = saleUser;
              });
          });
        });
      return sales;
    };
 });

如您所见,我正在获取所有销售,在它完成后,通过调用另一个 UsersService 循环获取和设置相关的用户详细信息,如下所示

angular.
  module('core.users')
  .service('UsersService', function ($firebaseArray,$firebaseObject) {
this.getUserDetail = function (userId) {
      var user;
      var refUser = firebase.database().ref('users/'+userId);
      user = $firebaseObject(refUser);
      return user;
    };
  });

到目前为止一切顺利,当我在控制器中调用 SalesService.getAllSalesJoin 函数并使用 <pre>{{$ctrl.allSales | json}}</pre> 打印 JSON 对象时,一切正常如我所愿,下面是控制器代码并在模板中打印了 JSON 对象。

angular.
  module('saleList').
  component('saleList', {
    templateUrl: 'MCTs/sale-list/sale-list-template.html',
    controller: ['SalesService','UsersService', function SaleListController(SalesService,UsersService,$scope) {

          this.allSales = SalesService.getAllSalesJoin();  
 }]
  });

模板显示合并后的对象

{
  "$id": "sales",
  "$priority": null,
  "-KQlb5N6A9rclc5qcWGD": {
    "price": 8,
    "quantity": {
      "count": 12,
      "type": "porsiyon"
    },
    "status": "sale",
    "title": "Patlicanli Borek",
    "user": {
      "$id": "-KQ52OJd-lwoDIWzfYFT",
      "$priority": null,
      "address": "Izmir kaynaklar",
      "email": "ayse@gmail.com",
      "name": "Ayse Kahraman",
      "nick": "Ayse'nin Mutfagi"
    }
  },
  "-KQlcScsq8cidk7Drs04": {
    "price": 12,
    "quantity": {
      "count": 10,
      "type": "porsiyon"
    },
    "status": "sale",
    "title": "Deneme",
    "user": {
      "$id": "-KQ5-mZBt6MhYy401gGM",
      "$priority": null,
      "address": "Halkali kucukcekmece",
      "email": "burak.kahraman@gmail.com",
      "name": "Burak Hero",
      "nick": "Burak'in Mutfagi"
    }
  },
.....

但是问题是,当服务器数据发生变化时(输入新销售或删除旧销售),angular自动理解变化但它应用在不实现或调用我的连接函数的情况下更改视图,它只打印 销售对象 而不是与用户合并的对象。以下为服务器数据变更后的展示对象

{
  "$id": "sales",
  "$priority": null,
  "-KQlb5N6A9rclc5qcWGD": {
    "price": 8,
    "quantity": {
      "count": 12,
      "type": "porsiyon"
    },
    "status": "sale",
    "title": "Patlicanli Borek",
    "user": "-KQ52OJd-lwoDIWzfYFT"
  },
  "-KQlcScsq8cidk7Drs04": {
    "price": 12,
    "quantity": {
      "count": 10,
      "type": "porsiyon"
    },
    "status": "sale",
    "title": "Deneme",
    "user": "-KQ5-mZBt6MhYy401gGM"
  },
....

我很困惑为什么它会这样?我使用 $loaded 实现连接的方法错了吗?或者我应该使用另一种方法来实现这种连接?我期待看到您宝贵的建议和想法。

$loaded() 仅在加载初始数据时触发。来自 reference documentation(强调我的):

Returns a promise which is resolved when the initial object data has been downloaded from the database.

这就是我常说的主要原因:"if you're using $loaded(), you're doing it wrong".

您说得对,需要将数据与多个调用结合起来。在 AngularFire 中你可以 extend $firebaseArray to perform such an operation. For a great example of how to do this, see this answer by Kato:

感谢指导@Frank。我阅读了您的所有建议并找到了解决方案。为了贡献 Whosebug 知识并帮助他人,这里是问题的完整解决方案。

我首先创建了一个新工厂,它扩展了 $firebaseArray 并覆盖了 $$added 和 $$updated 方法,以便在每次更新或添加数据时对 Users 对象执行 join .

angular.
  module('core.sales').factory("SalesFactory", function ($firebaseArray, Sales) {
    return $firebaseArray.$extend({
      $$added: function (snap) {
        return new Sales(snap);
      },

      $$updated: function (snap) {
        return this.$getRecord(snap.key).update(snap);
      }

    });
  });

angular.
  module('core.sales').factory("Sales", function ($firebaseArray, $firebaseObject) {
    var refUsers = firebase.database().ref('users');

    function Sales(snapshot) {
      this.$id = snapshot.key;

      this.update(snapshot);
    }

    Sales.prototype = {
      update: function (snapshot) {
        var oldTitle = angular.extend({}, this.title);
        var oldPrice = angular.extend({}, this.price);
        var oldQuantity = angular.extend({}, this.quantity);

        this.userId = snapshot.val().user;
        this.title = snapshot.val().title;
        this.status = snapshot.val().status;
        this.price = snapshot.val().price;
        this.quantity = snapshot.val().quantity;
        this.userObj = $firebaseObject(refUsers.child(this.userId));

        if (oldTitle == this.title && oldPrice == this.price && 
        oldQuantity.count == this.quantity.count && oldQuantity.type == this.quantity.type)
          return false;
        return true;

      },

    };

    return Sales;
  });

如您所见,SalesFactory 使用另一个名为 Sales 的工厂。在那个特定的工厂中,我检索了 Sales 对象的所有属性并将它们中的每一个分配给它对应的 属性。这就是我通过创建新的 属性 来执行加入用户对象的情况:this.userObj 缺少一件事就是调用新工厂而不是 $firebaseArray

this.getAllSalesArray = function () {
      var sales;
      var refSales = firebase.database().ref('sales');
      sales = SalesFactory(refSales);
      return sales;
    };

总而言之,所有与相关 User 连接的 Sales 对象都打印到视图中,

[
  {
    "$id": "-KQlb5N6A9rclc5qcWGD",
    "userId": "-KQ52OJd-lwoDIWzfYFT",
    "title": "Patlicanli Borek",
    "status": "sale",
    "price": 12,
    "quantity": {
      "count": 11,
      "type": "tabak"
    },
    "userObj": {
      "$id": "-KQ52OJd-lwoDIWzfYFT",
      "$priority": null,
      "address": "İzmir kaynaklar",
      "email": "ayse@gmail.com",
      "name": "Ayşe Kahraman",
      "nick": "Ayşe'nin Mutfağı"
    }
  },
  {
    "$id": "-KQlcScsq8cidk7Drs04",
    "userId": "-KQ5-mZBt6MhYy401gGM",
    "title": "Deneme",
    "status": "sale",
    "price": 12,
    "quantity": {
      "count": 10,
      "type": "porsiyon"
    },
    "userObj": {
      "$id": "-KQ5-mZBt6MhYy401gGM",
      "$priority": null,
      "address": "Halkalı küçükçekmece",
      "email": "burak.kahraman@gmail.com",
      "name": "Burak Hero",
      "nick": "Burak'ın Mutfağı"
    }
  },
...
]