1

I have a form which I want to be sent only if the user provided a valid access key ($scope.access_key) - and each key can be used only once.

In my controller I have a following method:

$scope.verifyAccess = function() {
    var ref = new Firebase(FBURL+'/keys');
    var sync = $firebase(ref);  
    $scope.keys = sync.$asArray();
    var success = false;
    $scope.keys.$loaded( function(KEYS) {
        for( var i = 0; i < KEYS.length; i++ ) {
            var e = KEYS[i];
            console.log(e.key + " " + e.used);
            if( e.key === $scope.access_key && e.used == false ) {
                e.used = true;
                $scope.keys.$save(i);
                success = true;
                break;
            }
        }
        if( success ) {
            console.log("success");
            return true;
        } else {
            console.log("failure");
            return false;
        }
    });         
}

And then I use it like this:

$scope.addSurvey = function() {
    if( $scope.verifyAccess() ) {
        // do something
        alert("OK");
    }
};

When I call $scope.addSurvey() I see "success" in my log (and the database is modified properly), but alert("OK") doesn't fire.

If I don't use $loaded, method returns immediately and doesn't wait for the data to be loaded and processed. On the other hand, if I use $loaded, it doesn't seem to return anything at all.

What am I doing wrong?

machaerus
  • 641
  • 1
  • 5
  • 15
  • Keenan has the right of it. In addition to his answer, see these: http://stackoverflow.com/questions/27049342/asynchronous-access-to-an-array-in-firebase/27050749#27050749, http://stackoverflow.com/questions/26268446/trying-to-get-child-records-from-firebase/26277382#26277382, http://stackoverflow.com/questions/26297654/passing-variable-in-parent-scope-to-callback-function/26299662#26299662 and probably a few others. – Frank van Puffelen Dec 26 '14 at 19:25

1 Answers1

2

According to the documentation, $loaded() "Returns a promise which resolves after the initial records have been downloaded from Firebase." You can chain functions on that promise using .then, or just passing 1 callback as an argument, as you did above. However, you're returning from that callback, not from $scope.verifyAccess.

You're going to have to morph this into more asynchronous code. There's a few ways to do this; you could make $scope.verifyAccess update some hasAccess variable to true & then return a promise. Then $scope.addSurvey would look something like:

$scope.addSurvey = function() {
  $scope.verifyAccess()
    .then(function(){
      if( hasAccess ){
        // do something
        alert("OK");
    });
};

The above approach requires use of a promise library, which is valuable to learn and become familiar with. Alternatively, you can let $scope.verifyAccess take a callback that's executed once it actually verifies if a user has access:

$scope.verifyAccess = function(callback) {
    var ref = new Firebase(FBURL+'/keys');
    var sync = $firebase(ref);  
    $scope.keys = sync.$asArray();
    var success = false;
    $scope.keys.$loaded( function(KEYS) {
        for( var i = 0; i < KEYS.length; i++ ) {
            var e = KEYS[i];
            console.log(e.key + " " + e.used);
            if( e.key === $scope.access_key && e.used == false ) {
                e.used = true;
                $scope.keys.$save(i);
                success = true;
                break;
            }
        }
        if( success ) {
            console.log("success");
            callback();
        } else {
            console.log("failure");
        }
    });         
}
  • Thanks a lot, I followed the first approach and it works great. Additionaly, I used [these examples](https://docs.angularjs.org/api/ng/service/$q) to modify `verifyAccess()` so that it returns a promise. – machaerus Dec 27 '14 at 16:31
  • Great answer Keenan. @machaerus, returning the promise works great for a lot of use cases. It allows you to create some sophisticated chains, use it in routes with `resolve` and do other amazing async constructs. – Kato Dec 30 '14 at 19:32