Angularfire - Issue with $scope not updating after asynchronous call, causing error when using $apply

Struggling to grasp the inner workings of Angularfire in this particular scenario. On my "webapp/test" page, I have two controllers - one for user login and another for displaying profile information. When a user logs in with Facebook, I use their unique "uid" to query the firebase database for their information.

The issue arises because the database read operation is asynchronous, preventing me from updating the view. Even using $scope.$apply() only functions until I navigate to a page with a different controller, resulting in the following error:

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>

Answer №1

Don't forget, you're utilizing the Firebase SDK without AngularFire in this scenario.

Angular doesn't recognize the Firebase SDK on its own, so using AngularFire is necessary to activate the $digest loop.

To incorporate AngularFire, make sure to include the JavaScript file and 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);
}

Key points from your original code to consider.

Avoid using Promises as real-time listeners, as it's not recommended.

Promises execute only once, while Firebase database listeners can trigger multiple times.

ref.on("value", function(snapshot) {
  var userDatabase = snapshot.val();
  def.resolve(userDatabase); // avoid doing this
 }, function (errorObject) {
  console.log("The read failed: " + errorObject.code);
});

When working with AngularFire and either $firebaseObject or $firebaseArray, this issue is automatically handled.

Utilize resolve in the router for injecting users

Instead of fetching the user in the controller manually, ensure that authenticated users are injected using resolve in the router:

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for maximizing page layout efficiency without compromising on element visibility

What is occurring https://i.stack.imgur.com/Agjw6.gif The use of .hide() and .fadeIn(200) is resulting in a jittery effect that I would like to avoid. Desired Outcome When the user hovers over the menu icon, the menu icon should vanish the text "Pr ...

What could be causing the delay in Handlebars.js binding process after the initial run?

I'm facing a puzzling issue with my Handlebars.js template. Initially, it efficiently renders data into a table without any hiccups. However, subsequent runs take an unexpectedly long time (even with the same data!) and sometimes result in browser cra ...

This code snippet results in the property being unrecognized

I recently wrote this block of code and encountered an error while trying to run the alert function. It keeps telling me that 'this.words' is not defined. I suspect the issue lies within the jQuery portion, as I am able to access the array where ...

Javascript does not function on sections generated by ajax

I'm facing an issue with a JavaScript function not working on a dynamically generated part using AJAX. Here is the AJAX call: <script> $(window).on('scroll', function() { $("#preloadmore").show(); if ($(window).height() + $(window ...

Retrieve the initial index from a sorted array in JavaScript using an array

'I am looking to organize an array in numerical order, but I also need to be able to track the original index of each element after sorting. Consider the initial array: ptsGP = [3,8,2,5,6,9,8,4] Below is the code I am currently using to sort the ar ...

Issues with ng-model within a custom directive

Struggling with my first non-trivial directive and encountering some issues. Attempting something similar to http://plnkr.co/nYSBnm Although the functionality is correct, both inputs end up using the same field. Trying to assign them to different fields ...

Creating a log-out script in Parse (JavaScript) can be achieved by following these steps

I'm facing an issue with logging out from my website. Despite browsing through Parse's documentation, I couldn't find a detailed explanation on how to log out the user, especially since I'm not well-versed in JavaScript. Whenever I cli ...

Retrieve the file for saving using the HttpPost method in Asp.Net MVC

In my Asp.Net MVC project, there is a page where users can edit data loaded into a table, such as changing images, strings, and the order of items. Once all edits have been made, the client clicks on a Download button to save the resulting xml-file on the ...

What is the process for pushing a JSONObject to a specific node in a Firebase database?

Currently in the process of transitioning an app to firebase from a SQLDatabase. Successfully converted the database to a JSONObject. Wondering if there's a way to simply populate a user node in firebase with this object? Attempted to write the JSONO ...

Ways to maintain an active session until the user specifically logs out

As I work on my asp.net website, I face the challenge of sessions expiring automatically after hosting. While everything functions normally on my local host, once hosted, problems arise with session expiration after a few minutes. My goal is to maintain an ...

What is the established procedure for resetting all elements within an (X)HTML document?

Is there a way to reset elements without using a form like how it can be done with JavaScript? document.forms[0].reset(); I am utilizing AJAX, so do I need to loop through all the elements using JavaScript? ...

Exploring ways to retrieve a video thumbnail with VueJS3

I am currently working on a project to create a simple program that retrieves movies from my AWS-S3 bucket and transforms them into picture thumbnails. Below is the code I have written: <template> <img :src="imgURL" class="card- ...

Tips for creating a Selenium Java logic that dynamically switches between two paths depending on the type of question

Currently, I am developing a logic in selenium-java to automate the process of taking tests. During this testing phase, each test-taker may receive either set-1 or set-2 at random for each node. The number of questions in each set may vary Answer data wil ...

Is it possible for me to utilize pure JavaScript for loading JSON data?

I am interested in dynamically creating a Google Map by loading data through AJAX. To achieve this, I am using a JSON object that mimics the structure of the GM API to construct the map and jQuery for AJAX loading. For example: "object": { "div": "ma ...

The return value of a jQuery post request is consistently false

When I click on a tag, my code returns true but the data variable is false. Can you explain why this is happening? $('#AddProvince').click(function () { var url = '@Url.Action("SetProvinceList")'; var id = $('#Province&apo ...

What steps are required to run this Go program on a local machine?

Is it possible for me to run the application locally on my machine from the repository https://github.com/jbowens/codenames? Here are the steps I've attempted: I installed Go and added the PATH variable. I cloned the repository to the correct go p ...

What are the steps to inject the npm package called lodash as a dependency injection in AngularJS for the angular-google-maps module with the help

I have set up my angular application using npm as the package manager and Browserify to manage libraries. The specific package I am using is angular-google-maps from http://angular-ui.github.io/angular-google-maps. An error message I encountered is: Refe ...

Deactivate the ValueEventListener()

Can anyone assist me with this issue? I am trying to use "addListenerForSingleValueEvent" to retrieve a list of values, and before that, I display a progressDialog. However, sometimes the network connection is too slow, causing the value retrieval to take ...

The values obtained from the previous parameter object of the React setState hook can vary and are not always

In my code, I am using a useEffect hook to update the state with setState. However, I'm encountering some unusual and inconsistent behavior with the previous parameter: useEffect(() => { setCurrentPicturesObject((existing) => { ...

Removing an array from a nested array using JQuery's key functionalities

I need help removing an array from a multidimensional array if the id matches a given one. var test_arr = [{"name":"qqq", "city":"it","id":"123456"}, {"name":"ggg", "city":"uk","id":"777456"}]; var result = test_arr.filter(function(v,i) { if (v[0] ...