在 Observable Subject 上调用 onError 时如何在 angularJs 应用程序中刷新视图

How to refresh view in angularJs app when onError called on Observable Subject

我有一个 AngularJs 应用程序并使用 RXJS。我有一项服务等待用户允许或拒绝访问 OAuth 提供商并具有此签名:

authorise( requestDetails : IRequestDetails ) : Rx.Observable<string>;

当允许访问并且我取回访问令牌时,我将其传回控制器,如下所示:

request.observable.onNext( request.access_token );
request.observable.onCompleted();

并且控制器通过更新消息的支持者变量将其传递回视图:

    private _message : string = "Awaiting authorisation";

    get message() : string {
        return this._message;
    }

    authenticate() : void
    {
        this._oAuthService.authorise( Example.googleAuthDetails ).subscribe(
            ( result : string ) => this.handleAuthorisation( result ),
            ( fault : string ) => this.handleError( fault )
        );
    }

    private handleAuthorisation( result : string ) : void {
        this._message = result;
    }

一切正常。我发现它在这种情况下起作用的原因是因为 onNext 调用是作为 $http 调用结果的一部分进行的。此调用包含在触发摘要循环的 $apply 调用中。 但是,当用户拒绝访问时,我会在可观察对象上调用 onError:

    request.observable.onError( "access token denied" );
    request.observable.onCompleted();

并且在控制器中我用错误更新了字符串:

    private handleError( fault : string ) : void {
        this._message = fault;
    }

但在这种情况下,视图不会更新,显示的字符串仍为 "Awaiting Authorisation"。 在这种情况下,由于授权被拒绝,因此不会进行任何 $http 调用,并且会在未包含在 $apply 调用中的函数中触发控制器。

我已将 rx.angular.js 库包含在我的 html 页面中,希望它会自动修复它,但它没有。阅读文档似乎我可能需要专门看一些东西。我认为我可以让它与 RXJS 一起工作,并在更新时始终更新范围。 如果不需要,我不想将范围注入我的控制器以强制刷新。我不喜欢依赖它。

可以在这个分支中查看整个项目:

https://github.com/Roaders/Typescript-OAuth-SPA/blob/rxjs_issues/index.html

只需将所有内容包装到一个 $timeout 调用中,它将确保调用摘要。

RX.angular 看起来不错,但我认为不在任何地方使用 $scope 的新规范有点过时了。

var myAppModule = angular.module('myApp', []).controller('ctrl', SettingsController1);

function SettingsController1($timeout) {

  this.message = "waiting";
  this.observable = new Rx.ReplaySubject(2 /* buffer size */ );
  var _this = this;
  this.observable.subscribe(
    function(x) {
      $timeout(function() {
        _this.message = x;
      }, 0);
    },
    function(err) {
      $timeout(function() {
        _this.message = err;
      }, 0);
    },
    function() {
      this.message = 'completed';
    });

  this.success = function() {
    this.observable.onNext('success');
  }

  this.error = function() {
    this.observable.onError('failed');
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.min.js"></script>

<div ng-app="myApp" ng-controller="ctrl as ctrl">
  <div>
    {{ ctrl.message }}
  </div>
  <button ng-click="ctrl.success()">
    Success
  </button>
  <button ng-click="ctrl.error()">
    Error
  </button>
</div>

这个解决方案在这个分支中实现:https://github.com/Roaders/Typescript-OAuth-SPA/tree/rx_solved_with_timeout

它在错误情况下不起作用的原因是因为没有 http 调用来触发摘要循环,所以我们需要在这种情况下触发摘要循环。

为此,我们需要将 $rootScope 注入到服务中,当我们调用 onError 时,我们需要将其包装在 $rootScope.$apply 调用中:

        this._scope.$apply( () => {
            request.observable.onError( "access token denied" );
            request.observable.onCompleted();
        } );

这个解决方案在这里: https://github.com/Roaders/Typescript-OAuth-SPA/tree/rx_solved_with_scope

我知道我说过我不想注入作用域,但现在我更好地理解了为什么需要注入,我认为我可以接受。我也更乐于注入根作用域,而不是注入不用于任何其他用途的控制器作用域。