Angularfire - $ scope is not updated after an asynchronous call and $ apply throws error

I am currently banging my head trying to understand a little better how Angularfire works in this case. I have two controllers on my "webapp / test", one for logging in and the other for displaying profile information. After logging in with Facebook, I use "uid" to check the firebase database, if the user exists, and retrieves some of the information stored in the database.

The problem is right now if, because the request to read the isync database, I can’t get the update information in the view, and using $scope.$apply() only works until I change the pages as soon as I click on a page 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: Preview

This is my opinion, what I'm trying to do is when the user is logged in, show some information from the firebase structure belonging 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> 
+5
source share
1 answer

You are not actually using AngularFire , just the Firebase SDK.

Angular does not know about the Firebase SDK, so you need to use AngularFire so that it runs the $ digest loop for you.

To enable AngularFire, add a JavaScript file, and then add it to the dependency array.

 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); } 

Some notes in the source code.

You are using Promise, a real-time listener that is an anti-template.

Promises only fires once, while Firebase database listeners can fire several 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 will take care of this for you if you use either $firebaseObject or $firebaseArray .

Use resolve in the router for user input

Instead of capturing the user in the controller, you can make sure that if the user is authenticated, they will be entered into the controller:

 app.config(["$routeProvider", function($routeProvider) { $routeProvider.when("/home", { controller: "HomeCtrl", templateUrl: "views/home.html", resolve: { currentAuth: ["Auth", function(Auth) { return Auth.$requreAuth(); }] } }) 
+3
source

Source: https://habr.com/ru/post/1239051/


All Articles