Search code examples
javascriptangularjstypescriptangularjs-scope

AngularJS 1.5: scope.$watch inside link function doesn't update on model change


Good day to everyone!

I'm developing a web app, using typescript and angular 1.5;

I've created a directive the main goal of wich is to spy on whether user logged in or not, and hide/show corresponding element.

Here is the link function code:

interface ShowAuthedScope extends ng.IScope{
  User: UserService,
  _$log: ng.ILogService
}

function ShowAuthedDirective(User:UserService, $log:ng.ILogService) {
  'ngInject';

  return {
    restrict: 'A',
    link: function (scope, element, attrs) {
      scope.User = User;
      scope._$log = $log;
      scope.$watch('User.current', function (val) {
        scope._$log.log('updated!:', val);
      })
    }
  }
}

The model for my case is the current user, that being set or unset depending on whether he is logged in or not.

here is the clipped code for the UserService:

interface UserInterface {
  current:GoogleUser;
  signIn(options?:SignInOptions):Promise<any>;
  signOut():Promise<void>;
}

class UserService implements UserInterface {
  public current:GoogleUser;
  private _GoogleAuth:GoogleAuthService;
  private _AppConstants;

  constructor(GoogleAuth:GoogleAuthService, AppConstants) {
    'ngInject';
    this._GoogleAuth = GoogleAuth;
    this._AppConstants = AppConstants;
    this.current = null;
  }

  public signIn(options?:SignInOptions) {
    let promise:Promise<any>;
    let _options:SignInOptions = options || {};
    _options.app_package_name = this._AppConstants.appPackageName;
    if (this.current) {
      promise = this.current.signIn(_options);
    } else {
      promise = this._GoogleAuth.signIn(_options);
    }
    promise = promise.then((googleUser:GoogleUser) => this.current = googleUser);
    return promise;
  }


  public signOut() {
    this.current = null;
    return this._GoogleAuth.signOut();
  }

}

The function inside $watch gets triggered only once after initializing;

Also note, that I already tried to pass true as the third parameter of the $watch function

Hope for your help! Thanks!


Solution

  • When you call signIn and signOut from the console, it happens outside something called a "Digest Cycle". Angular runs $watch statements in every digest cycle, but there needs to happen something that triggers it.

    For example ng-click and all Angular event handlers automatically trigger digest cycle so that variable changes can be detected.

    So in summary, if you want to do everything from the Console, you need to trigger digest cycle yourself:

    angular.element(document).injector().get('$rootScope').$digest()