angular / angular.js

AngularJS - HTML enhanced for web apps!
https://angularjs.org
MIT License
58.81k stars 27.49k forks source link

Typescript service class and $rootScope inject #14152

Closed artaommahe closed 8 years ago

artaommahe commented 8 years ago

Using typescript class for service that injects $rootScope like this

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

will falls with this errors

Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: []
Error: [ng:cpws] Can't copy! Making copies of Window or Scope instances is not supported.

it happens becasue $rootScope saves as accesible function variable after transpiling

function Settings($rootScope) {
  var _this = this;
  this.rootScope = rootScope;
}

and angular trying to hang watch

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

and falls with copy

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

based on this staskoverflow question http://stackoverflow.com/questions/33814040/how-do-i-inject-rootscope-using-typescript-static-injector-pattern/35710099#35710099

gkalpak commented 8 years ago

I'm not able to reproduce it (exaple attempt). Could you post a live reproduction (e.g. using CodePen, Plnkr etc) ?

dpogue commented 8 years ago

One nice solution to the general problem of injecting things and TypeScript that we've come up with is to only inject the $injector (if possible).

class MyService {
  private $injector : ng.auto.IInjectorService;

  static $inject = ['$injector'];
  constructor($injector : ng.auto.IInjectorService) {
    this.$injector = $injector;
  }

  someMethod() {
    let $rootScope = this.$injector.get<ng.IRootScopeService>('$rootScope');
    // ...
  }
}

This avoids needing to have all the injectables you want to use as instance variables on your service.

gkalpak commented 8 years ago

On the downside, using the $injector might cover up cyclic dependencies. This is not specific to TypeScript; it's also true with JavaScript.

thorn0 commented 8 years ago

@artaommahe See my answer on SO.

Narretz commented 8 years ago

I think this is expected behavior. This could also happen with non-Typescript code. You simply should not watch the whole instance as @thorn0 has written in his SO answer.