解决 Firebase GetRecord 之前视图加载不完整的问题

Incomplete View Loading Before Firebase GetRecord is Resolved

我在将记录从 firebase 加载到我的视图中时遇到问题,当直接 link 使用密钥作为 routeParam 进入预期路线时。如下所示,在我的 routeProvider 中,我指定了稍后在 SpecController 中调用的参数。问题是,如果我直接键入 url 或单击异地 link,则模型绑定都是 "undefined",表明未加载记录。

// Snippet from RouteProvider
.when('/spec/:urlKey', {
  templateUrl: 'views/spec.html',
  controller: 'SpecController',
  controllerAs: 'spec'
})

// Snippet from SpecController
var cKey = $routeParams.urlKey;
this.check = this.checkList.$getRecord(cKey);

经过一番研究,我似乎应该在路由提供程序中调用解析,运行 第二段代码。虽然我不确定这是否是问题所在,或者它是否与 angular 加载自身的方式和路由参数及其顺序有关。

作为旁注,当我从单独的 route/view 加载应用程序然后单击应用程序中的 link 然后使用 $location 设置 url 和参数如下所示。

// Snippet from ListController
this.viewCheck = function(check){
  var ref = this.checkList.$keyAt(check);
  $location.path('/spec/'+ref);
};

我指的 "key" 以及我正在使用和指的所有其他附加功能可以直接在 Firebase API 指南的以下部分找到:https://www.firebase.com/docs/web/libraries/angular/guide.html#section-arrays

我无法在 fiddle 中真正重现该问题,因为它发生的唯一方法是直接将 link 放在浏览器的 url 中。我制作了一个显示问题的小视频。当视频打开时,您会看到直接输入 url 的结果,然后只需单击 "Home",然后单击 "Back",它就会正确加载。 http://screencast.com/t/4OKRTVnc

如评论中所述,您应该使用 Angular 基于承诺的路由解析过程。这里有一个working plunkr demonstration,但是亮点是:

构建 Returns Angularfire 的承诺

的数据服务

构建和访问 Firebase 数据的方法有很多,但这里重要的是使用由 Angularfire 编写的 return 承诺。这可以防止您为相同的数据创建重复的同步对象,并允许您使用 Angular.

testApp.factory("ChatDataService", ["$firebase", 
  function ($firebase) {
    var rootRef = new Firebase("https://docs-examples.firebaseio.com/");
    var chatDataService = {};

    chatDataService.getChatRooms = function () {
      if (!chatDataService.chatRoomsPromise) {
        var chatRoomRef = rootRef.child("web/data/rooms");
        var chatRooms = $firebase(chatRoomRef).$asArray();
        chatDataService.chatRoomsPromise = chatRooms.$loaded();
      }
      return chatDataService.chatRoomsPromise;
    };

    chatDataService.getRoom = function (roomId) {
      return chatDataService.getChatRooms()
        .then(function (chatRooms) {
          return chatRooms.$getRecord(roomId);
        });
    };

    chatDataService.getRoomMessages = function (roomId) {
      if (!chatDataService.messages || !chatDataService.messages[roomId]) {
        chatDataService.messages = chatDataService.messages || {};
        var roomMessagesRef = rootRef.child("web/data/messages").child(roomId);
        var roomMessages = $firebase(roomMessagesRef).$asArray();
        chatDataService.messages[roomId] = roomMessages.$loaded();
      }
      return chatDataService.messages[roomId];
    }; 

    return chatDataService;
  }
]);

Return 解析函数的承诺

您可以编写一个小型路由解析函数,使用您的数据服务来获取正确的数据。确保你return一个承诺。

  when("/room/:roomId", {
      controller: "RoomController",
      resolve: {
          room: ["$route", "ChatDataService", function ($route, chatDataService) {
              var roomId = $route.current.params.roomId;
              return chatDataService.getRoom(roomId);
          }],
          messages: ["$route", "ChatDataService", function ($route, chatDataService) {
              var roomId = $route.current.params.roomId;
              return chatDataService.getRoomMessages(roomId);
          }]

      },
      templateUrl: "roomView.html"
  })

让你的控制器保持沉默

您本可以在每个控制器中完成所有 Firebase 查找和承诺解析。在这种情况下,我通过让 Angular 路由等待 promise 解析来让控制器保持沉默。

testApp.controller("RoomController", ["$scope", "$firebase", "room", "messages",
  function ($scope, $firebase, room, messages) {
    $scope.room = room;
    $scope.messages = messages; 
  }
]);