解决 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;
}
]);
我在将记录从 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;
}
]);