A colleague claims this is an incorrect way to inject a pure ES6 JavaScript class into Angular. I am curious if there is a better way (more correct)?
As an aside, is it better (and why is it better) to attach the injected dependencies ($timeout
in this example) to the instance; e.g., this._$timeout = $timeout
in the constructor. I personally think there is no advantage to doing that in this case.
class.factory.js
let ClassFactory = function($timeout) {
// Factory function that simply returns class constructor.
class MyClass {
constructor(a, b) {
// contrived class
this.a = a;
this.b = b;
this.c = null;
}
applyChange() {
// contrived class method
const SELF = this;
$timeout(() => {
SELF.c = SELF.a + SELF.b;
});
}
}
return MyClass ;
};
ClassFactory.$inject = ['$timeout'];
export default ClassFactory;
app.module.js
import ClassFactory from './factories/class.factory';
import AppService from './services/app.service';
export default angular.module('myApp', [])
.factory('ClassFactory', ClassFactory)
.service('AppService', AppService);
Later, elsewhere we may use the class in some service or controller, to construct new MyClass instances.
app.service.js
class AppService {
// contrived usage of our dependency injected pure class.
constructor(ClassFactory) {
this.array = [];
this._ClassFactory = ClassFactory;
}
initialize(a, b) {
// We can instantiate as many "MyClass" objects as we need.
let myClass = new this._ClassFactory(a, b);
this.array.push(myClass);
}
static serviceFactory(...injected) {
AppService.instance = new AppService(...injected);
return AppService.instance;
}
}
AppService.serviceFactory.$inject = ['ClassFactory'];
export default AppService.serviceFactory;
At this point it doesn't matter if $timeout
is class property or just local variable.
Wrapping a class with factory function doesn't play well with ES6 development , it's not possible to export and extend it. The fact that a factory is needed probably indicates design problem.
A class like that can get the dependencies via dependency injection (in common sense). This is a usual thing when class constructor is supposed to be called with non-dependency arguments too:
export class MyClass {
constructor($timeout, a, b) {
this._$timeout = $timeout;
...
}
}
...
obj = new MyClass($timeout, a, b);
If there's more than one dependency, $injector
dependency can be provided instead of all dependencies:
export class MyClass {
constructor($injector, a, b) {
this._$timeout = $injector.get('$timeout');
...
}
}
...
obj = new MyClass($injector, a, b);
There may also be a design problem that causes the dependency on $timeout
, and by solving it the dependency could be avoided. It's not clear from the code above why MyClass
should trigger a digest with $timeout
, its logic doesn't contain anything that would require that. It's the responsibility of code that uses MyClass
instance and binds it to view or whatever a digest is there for.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With