Rodrigo Pereira
Rodrigo Pereira

Reputation: 1914

How to update $scope immediately when dealing with non angular code?

I have to deal with an non angular library and need to create a comunication between them.

<div id="MoipWidget" data-token="{{personaltoken}}" callback-method-success="successCB" callback-method-error="errorCB"></div>

Every time that the page is loaded, I have to get a token from my server.

$http.post('https://example.org', obj)
        .success(function(data){
            $scope.personaltoken = data.token;
            //Here I call the non angular library and I get and error telling me that the token is undefined.
            //If I run the code from inside a $timeout works as I need...

        })
        .error(function(data){
             alert('error');
        });

I've also tried to run inside $scope.$apply but I get an error telling that $digest already in progress

The non angularjs library that I have to call is simple is just two lines.

var settings = {} 
LibraryCall(settings);

How can I update the model immediately?

Upvotes: 2

Views: 566

Answers (3)

Rodrigo Pereira
Rodrigo Pereira

Reputation: 1914

I've tried to use $scope.$evalAsync as @Kjell suggested but did not work.

After reading more about $scope, I've found what I needed.

$scope.$applyAsync(function(){
    var settings = {} 
    LibraryCall(settings);
});

$scope.$applyAsync will schedule the invocation of $apply to occur at a later time.

https://docs.angularjs.org/api/ng/type/$rootScope.Scope

Upvotes: 2

Kjell Ivar
Kjell Ivar

Reputation: 1164

Try using either $scope.$evalAsync() or $scope.$applyAsync(). They are made for stuff like this. It will execute the code later in time. Not that different from $timeout, but potentially faster.

$scope.$evalAsync(function(){
    var settings = {} 
    LibraryCall(settings);
})

Edit: Just to quote Ben Nadel on the difference between $timeout and $evalAsync, from this post:

So, in essence, $scope.$evalAsync() combines the best of both worlds: When it can (which is most of the time), it will evaluate your expression in the same tick; otherwise, it will evaluate your expression in a later tick, which is exactly what $timeout() is doing.

Upvotes: 0

Eloims
Eloims

Reputation: 5224

I removed the error callback for brevity, don't do it in your code :)

I suppose the code you call is asynchronous, if it's not, you should not have any $scope updating problem (because all angular promises call $apply already)...

This should work:

$http.post('https://example.org', obj).success(function(data){
    $scope.personaltoken = data.token;

    otherLibrary.doSomething(data.token, function(error, result) {
        $scope.changeSomething = 'toHey';
        $scope.$apply();
    });
});

This shoud also work:

$http.post('https://example.org', obj).success(function(data){
    $scope.personaltoken = data.token;

    otherLibrary.doSomething(data.token, function(error, result) {
        $scope.$apply(function() {
            $scope.changeSomething = 'toHey';
        });
    });
})

This shoud raise the $digest already in progress error, because $http does wrap the promise callback on a $apply call already.

$http.post('https://example.org', obj).success(function(data){
    $scope.personaltoken = data.token;
    $scope.$apply(function() {
        otherLibrary.doSomething(data.token, function(error, result) {
            $scope.changeSomething = 'toHey';
        });
    });
})

Upvotes: 1

Related Questions