I am currently banging my head trying to understand a little bit better how Angularfire works in this case. I have 2 controllers on my "webapp/test", one for the user to login, and the other to show some profile info. After the user login with Facebook, i use the "uid" to check the firebase DB if the user exist, and retrieve some of the info thats saved on the database.
The problem right now if since the database read call is async, i cant get the info to update on the view, and using $scope.$apply()
only works as long as i dont change pages, once i click on a page thats using another controller, i get the following:
Error: [$rootScope:inprog] http://errors.angularjs.org/1.3.15/$rootScope/inprog?p0=%24digest
Controller
app.controller("profile", function($scope, loginService, Auth, userManagement) {
var authData = Auth.$getAuth();
if (authData != null) {
$scope.authData = authData;
userManagement.saveLastLogin(authData);
userManagement.userDatabaseRead(authData).done(function(userDatabase) {
$scope.userDatabase = userDatabase;
$scope.$apply();
});
};
$scope.logoutFB = function() {
loginService.logoutUser();
Auth.$onAuth(function(authData) {
$scope.authData = authData;
});
};
})
Factory
app.factory("userManagement",function(FirebaseUrl) {
return {
saveLastLogin: function(authData) {
var userId = authData.uid;
var ref = new Firebase(FirebaseUrl);
var users = ref.child("users");
var timestamp = Date.now();
users.child(authData.uid).update({
last_activity: timestamp,
});
console.log('user ' + userId + ' last login was on' + timestamp);
},
userDatabaseRead: function(authData) {
var ref = new Firebase(FirebaseUrl+"users/"+authData.uid);
var data, def = $.Deferred();
ref.on("value", function(snapshot) {
var userDatabase = snapshot.val();
def.resolve(userDatabase);
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
return def.promise();
},
}
});
Update 1: View
This is my view, what i am trying to do is once the user is logged in, show some information from the firebase structure that belongs to this user uid
<div class="jumbotron">
<h1>Profile View</h1>
<p ng-show="authData">Welcome {{ authData.facebook.cachedUserProfile.first_name }}</p>
<p ng-show="authData">{{userDatabase.last_activity | date:'yyyy-MM-dd HH:mm:ss Z'}}</p>
<button ng-click="logoutFB()" ng-show="authData" class="btn btn-danger facebook-login">Logout</button>
</div>
You're not actually using AngularFire, just the Firebase SDK.
Angular is not aware of the Firebase SDK, so you need to use AngularFire so it triggers the $digest loop for you.
To includle AngularFire, add the JavaScript file and then add it to the dependency array as well.
angular.module('app', ['firebase'])
.constant('FirebaseUrl', '<my-firebase-app>')
.service('rootRef', ['FirebaseUrl', Firebase])
.factory('userManagement', UserManagement)
.controller('MyCtrl', MyController);
function UserManagement($firebaseObject, rootRef) {
return {
saveLastLogin: saveLastLogin,
userDataseRead: userDatabaseRead
};
function userDataseRead(authData) {
var userRef = rootRef.child('users').child(authData.uid);
// return a $firebaseObject with the ref, don't create a listener
return $firebaseObject(userRef);
}
function saveLasLogin(authData) {
// this code is good because it doesn't do any listening,
// just updates to the server
}
}
function MyController($scope, userManagement) {
var authData = Auth.$getAuth();
$scope.userDatabase = userManagement(authData);
}
You're using a Promise is a real time listener, which is an anti-pattern.
Promises fire off only once, whereas Firebase database listeners can fire off multiple times.
ref.on("value", function(snapshot) {
var userDatabase = snapshot.val();
def.resolve(userDatabase); // don't do this
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
AngularFire takes care of this for you when you use either a $firebaseObject
or $firebaseArray
.
Use resolve
in the router to inject users
Rather than grab the user in the controller, you can ensure that if the user is authenticated they will be injected in the controller:
app.config(["$routeProvider", function($routeProvider) {
$routeProvider.when("/home", {
controller: "HomeCtrl",
templateUrl: "views/home.html",
resolve: {
currentAuth: ["Auth", function(Auth) {
return Auth.$requreAuth();
}]
}
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With