Search code examples
angularjsdeferredlawnchair

How to change view asynchronously in Angular JS (from Lawnchair JS)?


I have a fairly simple, 2-page web app. using Angular and Lawnchair. I have a login page from which I do not want to allow the screen/view to change until the user has been authenticated and relevant data has been pulled. Additionally, this is a mobile app. so the user may just need to be re-authenticated and their data loaded from their browser.

<!DOCTYPE html>
<html xmlns:ng="http://angularjs.org" ng:app="AppMod">
<head>
...
</head>
<body ng:controller="AppCtrl">
    <ng:view></ng:view>
    ...
</body>
</html>

When I use Lawnchair without an adapter, Angular changes views just fine and Lawnchair saves the data in the browser but not to something permanent like WebSQL or IndexedDB. However, as soon as one or more Lawnchair adapters are included, at worst the view will not display or at best it will update the location/URI without changing the view (until another event like 'change' is emitted).

$scope['login'] = function()
{
    AuthSvc.query(
        {'username':$scope['username'], 'password':$scope['password']},
        function( results )
        {
            LastUsedRsc.save({'key':'credentials', 'value':
                {'username':$scope['username'], 'password':$scope['password']}});
            $location.path( '/dataset' );
        },
        function( error )
        {
            alert( "Incorrect username and/or password." );
        });
    return( false );
};

I have tried $scope.$apply(), $scope.$digest(), their respective "safe" wrappers, etc. Here is a JSFiddle for your review. If you remove the Lawnchair adapters under Manage Resources and Run the fiddle again, you will see the views will start working, but Lawnchair is now worthless because nothing is truly persisted. What do I need to make views change while using one of Lawnchair's adapters?


Solution

  • You really need to run $digest or $apply after resolving the promises on LoginResolver and DatasetResolver.

    Example:

    var LoginResolver = {
        'credentialsAsync':function( $rootScope, $q, $route, LastUsedRsc ) {
            var deferred = $q.defer();
            LastUsedRsc.get( 'credentials', function( object ) {
                deferred.resolve( object );
                $rootScope.$digest();
            },
            function( error ) {
                window.console.info( "Using default, default value.", error );            
                deferred.resolve({'value':{}});      
                $rootScope.$digest();
            });
        return( deferred.promise );
        },
    };
    

    Note: You need to inject $rootScope and call $digest after resolve/reject.