【问题标题】:how do I inject `$rootScope` using TypeScript static injector pattern?如何使用 TypeScript 静态注入器模式注入`$rootScope`?
【发布时间】:2016-02-22 04:40:12
【问题描述】:

所以,最后在获得一个大型模型以 Angular 和 typescript 进行编译之后,我得到了这个运行时错误:

10angular.js:12314 错误:[ng:cpws] 无法复制!制作副本 不支持 Window 或 Scope 实例。 http://errors.angularjs.org/1.4.1/ng/cpws

at angular.js:68
at copy (angular.js:857)
at copy (angular.js:932)
at copy (angular.js:888)
at Scope.$digest (angular.js:15666)
at Scope.$apply (angular.js:15935)
at bootstrapApply (angular.js:1624)
at Object.invoke (angular.js:4443)
at doBootstrap (angular.js:1622)
at bootstrap (angular.js:1642)

我没有更改任何“实现”,我只是重新构造了类以使用 TypeScript。在我的代码中没有任何地方可以使用 angular.copy(在整个应用程序的任何类中)。在多次将头撞在墙上之后,我偶然发现了这个问题。构造函数将 $rootScope 分配给一个局部变量(由于 TS,它现在位于原型上)。现在,这是一种旧代码,我只使用 $rootScope 的 ref 将其用作所有使用 $rootScope.broadcast(...) 的视图控制器的通用事件调度程序。当我使用标准角度样板注入它时,它曾经工作正常,我可以重构它......

/// <reference path="../../app/reference.ts" />
class UserModel {
  roles:string;
  activeRole:string;
  errorString:string;
  loginAttemptEmailValue:string;
  successString:string;

static $inject = ['utils', '$rootScope','$q', '$cookies', '$http','settings', '$location'];
  constructor(u,r,q,c,h,s,l) {
    this.utils = u;
    this.rootScope = r; // <---- the problem. comment-out this line and it works.
    this.q = q;
    this.cookies = c;
    this.http = h;
    this.settings = s;
    this.location = l;
  }
...

angular.module('App').service('userModel', UserModel );

但这让我担心,当我去转换我的控制器时,我会遇到同样的问题,只是注入 $scope。

所以,我的问题是,我如何使用这个 TypeScript 静态注入器模式正确注入 $scope 而不会出现这个可怕的复制错误?

我尝试创建一个类级别的静态作用域变量,但在尝试分配给静态类型时当然会出现左侧赋值错误。

更新: 这是转译的js。

var UserModel = (function () {
    function UserModel(u, r, q, c, h, s, l) {
        var _this = this;

        this.utils = u;
        this.rootScope = r;
        this.q = q;
        this.cookies = c;
        this.http = h;
        this.settings = s;
        this.location = l;
    }
    UserModel.prototype.hasActiveRole = function (val) {
        if (this.activeRole === val) {
            return true;
        }
        return false;
    };
    //...other implementation...
    UserModel.$inject = ['utils', '$rootScope', '$q', '$cookies', '$http', 'settings', '$location'];
    return UserModel;
})();
angular.module('App').service('userModel', UserModel);

【问题讨论】:

  • 澄清请求:如果您注释掉this.rootScope = r;,那么您的应用仍然可以正常运行(减去广播)?
  • 是的!它是使应用程序立即出错的那一行。我可以将其注释掉,稍后在程序执行时得到一个正常的 null 错误。
  • 有道理,你能分享使用$rootScope的代码吗?你上面的作业是正确的。
  • 对,我只用来广播。 this.rootScope.$broadcast('changeRole'); 可能是另一个广播“loggedOut”之类的。我目前正在尝试将控制器转换为 TS,看看这实际上有多大意义。

标签: javascript angularjs angularjs-scope typescript


【解决方案1】:

所以,如果其他人碰到同样的砖墙,请在这里回答我自己的问题。我相信这种情况可能是 Angular 错误或缺少关于将 $rootScope 分配给服务中的局部变量的文档。

注入$scope 或$rootScope 并分配给本地引用属性似乎工作正常,在控制器中,但不是服务。我还注意到您无法将$scope 导入服务,也许角度团队也打算阻止注入$rootScope,但忽略了这样做。

错误本身令人费解;我最好的猜想是编译中存在一个工件(在 Angular 的内部深处),其中服务的实例化尝试深度复制 $rootScope 属性而不是浅复制当且仅当它被分配给服务对象上的属性时.

【讨论】:

    【解决方案2】:

    有同样的问题。就是这个东西

    at Scope.$digest (angular.js:15666)
    

    您将 UserModel 作为服务传递给 Angular,并在每个公共属性上添加 Angular 手表,包括所有这些

    this.utils = u;
    this.rootScope = r;
    this.q = q;
    this.cookies = c;
    this.http = h;
    this.settings = s;
    this.location = l;
    

    所以当 $digest 开始时,它会尝试save value as last

    watch.last = watch.eq ? copy(value, null) : value;
    

    然后 copy() 发生 :) 错误 because of

    if (isWindow(source) || isScope(source)) {
      throw ngMinErr('cpws',
        "Can't copy! Making copies of Window or Scope instances is not supported.");
    }
    

    我使用存储类的 rootScope 的外部变量临时解决了这个问题

    let rootScope: ng.IRootScopeService;
    
    class Settings() {
    
      static $inject = [
        '$rootScope'
      ];
    
      constructor($rootScope: ng.IRootScopeService) {
    
        rootScope = $rootScope;
      }
    }
    

    稍后将使用 RxJs Observables 替换 $rootScope 使用作为 pub/sub

    【讨论】:

      【解决方案3】:

      显然,您正试图深入观察您班级的整个实例。如果此对象的属性之一指向范围实例,则不应该这样做。如果您都想这样做,您可以尝试使用 getter 函数而不是普通属性:this.getRootScope = () =&gt; $rootScope,这可能有效,但听起来仍然不是一个好主意。因为出于性能原因,当您深度观察某物时,您希望被观察的对象尽可能小。如果你只是想检测一些数据的变化,那么同时寻找注入服务的变化是否有意义?显然,您将错误的对象传递给 $watch。

      (顺便说一句,我建议使用 ngAnnotate 而不是手写static $inject...。)

      【讨论】:

      • 没有手表。这只是将 $rootScope 注入服务的问题......除非有一些我不知道的自动绑定手表。
      • 堆栈跟踪清楚地显示某处有一个手表,它正在跟踪整个userModel 对象。像这样:$scope.$watch(userModel, ..., true).
      • 我看到了一个摘要,但没有手表。你指的是什么?
      • 实际上,消费控制器的实现只关注一个属性,loginStatus。 this.scope.$watch(() => { return this.userModel.loginStatus; }, (oldStatus, newStatus ) => { if( oldStatus !== newStatus ){ this.handleLoginStatusChange(); } });跨度>
      • Digest是手表加工的地方。 angular.copy 被深度手表用来存储被监视表达式值的副本。如果copy 是直接从$digest 调用的,则可能意味着仅这一件事。
      猜你喜欢
      • 2015-04-28
      • 2016-01-22
      • 2014-08-30
      • 2019-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-18
      • 1970-01-01
      相关资源
      最近更新 更多