I'm having a problem loading a record from firebase into my view when directly linking to the intended route with the key as a routeParam. As shown below in my routeProvider I've specified the param later called in the SpecController. The problem is, if I directly type the url in or click an offsite link the model bindings are all "undefined" indicating that the record is not loaded.
// 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);
After a bit of research it seems I should call a resolve in the routeprovider and run that second bit of code. Though I'm not sure if that's the problem or if it has to do with the way angular loads itself and the routeparams as well as the order thereof.
Just as a side note it is fully functional when I load the application from a separate route/view and then click a link within the application which then uses $location to set the url and param as shown below.
// Snippet from ListController
this.viewCheck = function(check){
var ref = this.checkList.$keyAt(check);
$location.path('/spec/'+ref);
};
The "key" I'm referring to as well as all other additional functions I'm using and referring to can be found directly at the following section of the Firebase API Guide: https://www.firebase.com/docs/web/libraries/angular/guide.html#section-arrays
I can't really reproduce the issue in a fiddle because the only way it happens is if you directly place the link in the url of a browser. I've made a small video showing the problem. When the video opens you see the result of entering the url directly, then by simply clicking "Home" and then "Back" it then loads appropriately. http://screencast.com/t/4OKRTVnc
As mentioned in the comments, you should use the Angular route resolution process based on promises. Here is a working plunkr demonstration, but the highlights are:
Build a Data Service that Returns Angularfire's Promises
There are many, many ways to structure and access your Firebase data, but the important thing here is to use the promises returned by Angularfire. This keeps you from making duplicate sync objects for the same data, and allows you to play nice with 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 Promises From Resolve Functions
You can write a small route resolution function that uses your data service to get the correct data. Make sure you return a promise.
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"
})
Keep Your Controllers Dumb
You could have done all the Firebase lookup and promise resolving in each controller. In this case, I kept the controllers dumb by letting Angular routing wait on promise resolution.
testApp.controller("RoomController", ["$scope", "$firebase", "room", "messages",
function ($scope, $firebase, room, messages) {
$scope.room = room;
$scope.messages = messages;
}
]);