Reading angular docs on dependency injection, there are two minification-friendly methods to do this:
Inline Array Annotation:
module.factory("MyStuff",['dependency',function(dep){...}])
The $inject property:
function MyStuff(dep) {...}
MyStuff.$inject = ['dependency'];
module.factory("MyStuff",MyStuff);
The inline one (first) is recommended. In one of my projects the style guide insists on the use of $inject property. I also see $inject property form quite often in open source code.
Hence the question:
What are the practical or technical benefits of using the $inject property form?
From the top of my head I came up with two, and they don't look very legit:
Creating instances of MyStuff directly:
new MyStuff(someOtherDependency).foo(...);
Having function name in console.log(myStuffInstance)
Anything else I am missing?
You should be using ng-annotate. If you are using build tool (you should), use the ng-annotate plugin with your build tool.
The main benefit of second approach is that it is module friendly.
class MyClass {
constructor($q) {}
}
MyClass.$inject = ['$q']
module.exprots = MyClass
You can use it like normal class
const MyClass = require('./myclass')
const foo = new MyClass($q)
or give it to angular
angular.service('MyClass', MyClass)
You can't really do
module.exports = ['$q', MyClass]
because it will make require('./myclass') unusable outside of angular
But if you are not using module or OOP, first approach is easier
angular.service('MyClass', ['$q', function ($q) {}])
There is no need to make a class for it
Related
I am gradually improving a codebase that originally had some AngularJs in various versions and some code that was not in a framework at all using various versions of a software API. (For some reason this API is available - to pages loaded through the application - on AngularJS's $window.external...go figure.)
In my pre-ES6, AngularJs 1.8 phase, I have three services that interact with the software's API (call them someAPIget, someAPIset, and someAPIforms). Something like this:
// someAPIget.service.js
;(function () {
var APIget = function ($window, helperfunctions) {
function someFunc (param) {
// Do something with $window.external.someExternalFunc
return doSomethingWith(param)
}
return {
someFunc: someFunc
}
}
angular.module('someAPIModule').factory('someAPIget', ['$window', 'helperfunctions', someAPIget])
})()
I then had a service and module a level up from this, with someAPIModule as a dependency, that aggregated these functions and passed them through under one name, like this:
// apiinterface.service.js
;(function () {
// Change these lines to switch which API service all functions will use.
var APIget = 'someAPIget'
var APIset = 'someAPIset'
var APIforms = 'someAPIforms'
var APIInterface = function (APIget, APIset, APIforms) {
return {
someFunc: APIget.someFunc,
someSettingFunc: APIset.someSettingFunc,
someFormLoadingFunc: APIforms.someFormLoadingFunc
}
}
angular.module('APIInterface').factory('APIInterface', [APIget, APIset, APIforms, APIInterface])
})()
I would then call these functions in various other controllers and services by using APIInterface.someFunc(etc). It worked fine, and if we switch to a different software provider, we can use our same pages without rewriting everything, just the interface logic.
However, I'm trying to upgrade to Typescript and ES6 so I can use import and export and build some logic accessible via command line, plus prepare for upgrading to Angular 11 or whatever the latest version is when I'm ready to do it. So I rebuilt someAPIget to a class:
// someAPIget.service.ts
export class someAPIget {
private readonly $window
private readonly helperfunctions
static $inject = ['$window', 'helperfunctions']
constructor ($window, helperfunctions) {
this.$window = $window
this.helperfunctions = helperfunctions
}
someFunc (param) {
// Do something with this.$window.external.someExternalFunc
return doSomethingWith(param)
}
}
}
angular
.module('someAPImodule')
.service('someAPIget', ['$window', 'helperfunctions', someAPIget])
Initially it seemed like it worked (my tests still pass, or at least after a bit of cleanup in the Typescript compilation department they do), but then when I load it into the live app... this.$window is not defined. If, however, I use a direct dependency and call someAPIget.someFunc(param) instead of through APIInterface.someFunc(param) it works fine (but I really don't want to rewrite thousands of lines of code using APIInterface for the calls, plus it will moot the whole point of wrapping it in an interface to begin with). I've tried making APIInterface into a class and assigning getters for every function that return the imported function, but $window still isn't defined. Using console.log statements I can see that this.$window is defined inside someFunc itself, and it's defined inside the getter in APIInterface, but from what I can tell when I try to call it using APIInterface it's calling it without first running the constructor on someAPIget, even if I make sure to use $onInit() for the relevant calls.
I feel like I am missing something simple here. Is there some way to properly aggregate and rename these functions to use throughout my program? How do alias them correctly to a post-constructed version?
Edit to add: I have tried with someAPIget as both a factory and a service, and APIInterface as both a factory and a service, and by calling APIInterface in the .run() of the overall app.module.ts file, none of which works. (The last one just changes the location of the undefined error.)
Edit again: I have also tried using static for such a case, which is somewhat obviously wrong, but then at least I get the helpful error highlight in VSCode of Property 'someProp' is used before its initialization.ts(2729).
How exactly are you supposed to use a property that is assigned in the constructor? How can I force AngularJS to execute the constructor before attempting to access the class's members?
I am not at all convinced that I found an optimal or "correct" solution, but I did find one that works, which I'll share here in case it helps anyone else.
I ended up calling each imported function in a class method of the same name on the APIInterface class, something like this:
// apiinterface.service.ts
// Change these lines to switch which API service all functions will use.
const APIget = 'someAPIget'
const APIset = 'someAPIset'
const APIforms = 'someAPIforms'
export class APIInterface {
private readonly APIget
private readonly APIset
private readonly APIforms
constructor (APIget, APIset, APIforms) {
this.APIget = APIget
this.APIset = APIset
this.APIforms = APIforms
}
someFunc(param: string): string {
return this.APIget.someFunc(param)
}
someSettingFunc(param: string): string {
return this.APIset.someSettingFunc(param)
}
someFormLoadingFunc(param: string): string {
return this.APIforms.someFormLoadingFunc(param)
}
}
angular
.module('APIInterface')
.factory('APIInterface', [APIget, APIset, APIforms, APIInterface])
It feels hacky to me, but it does work.
Later Update:
I am now using Angular12, not AngularJS, so some details may be a bit different. Lately I have been looking at using the public-api.ts file that Angular12 generates to accomplish the same thing (ie, export { someAPIget as APIget } from './filename' but have not yet experimented with this, since it would still require either consolidating my functions somehow or rewriting the code that consumes them to use one of three possible solutions. It would be nice not to have to duplicate function signatures and doc strings however. It's still a question I'm trying to answer more effectively, I will update again if I find something that really works.
I was reading an article of Max NgWizard K, about how Angular updates the DOM. I came across the following:
For each component that is used in the application Angular compiler generates a factory. When Angular creates a component from a factory Angular uses this factory to instantiate View Definition which in turn is used to create component View. Under the hood Angular represents an application as a tree of views.
In another article from Max NgWizard K I found the definition of a factory:
Factories describe the structure of a component view and are used when instantiating the component.
I'm not really sure what is meant with this.
Questions:
What exactly are factories in Angular(2+)?
Are there scenarios that a developer benefits form knowing how they work?
What exactly are factories in Angular(2+)?
Factory is one of the design patterns mentioned by Gang of Four (Basically they wrote a book on the design patterns they discovered).
Design Patterns help programmers solve common development tasks in a specific way.
And in this case, the Factory pattern helps in instantiation and creation of Objects.
It is also known as the Virtual Constructor.
Think of it, like this:
Say you are making a 2D shooter game, and you have to shoot bullets out of barrels.
Instead of instantiating bullets like new Bullet(), every time trigger is pulled, you can use a factory to create bullets, i.e. WeaponsFactory.createInstance(BulletTypes.AK47_BULLET).
It becomes highly scalable, since all you have to do is change the enum and the factory will make it for you.
You won't have to manually instantiate it.
That is what angular does, it automatically creates factory of all the components. Which makes its job easier.
Are there scenarios that a developer benefits form knowing how they work?
You don't have to know the inner workings of a Factory to use Angular, but it's useful for creating components dynamically!
e.g. A lot of *ngIf, or *ngSwitchCase can be replaced by a simple dynamic generation of components
Components can be created dynamically like this:
createComponent(type) {
this.container.clear();
const factory: ComponentFactory = this.resolver.resolveComponentFactory(AlertComponent);
this.componentRef: ComponentRef = this.container.createComponent(factory);
}
Reference for understanding the above code: Dynamically Creating Components
'A factory' in this case is an instance of ComponentFactory, a class that has create method that implements Factory method pattern.
When componentFactory.create is called (either directly or via ComponentFactoryResolver - which is essential for dynamic components, as linked article explains), new component instance is created.
In general factory is a creational design pattern. It is an object for creating other objects – formally a factory is a function or method that returns objects of a varying prototype or class from some method call.
From the Angular docs
#Component({
selector: 'app-typical',
template: '<div>A typical component for {{data.name}}</div>'
)}
export class TypicalComponent {
#Input() data: TypicalData;
constructor(private someService: SomeService) { ... }
}
The Angular compiler extracts the metadata once and generates a
factory for TypicalComponent. When it needs to create a
TypicalComponent instance, Angular calls the factory, which produces a
new visual element, bound to a new instance of the component class
with its injected dependency.
This is something which happens behind the scenes. But you create dynamic components using ComponentFactoryResolver as well (Dynamic component loader)
//Only dynamic component creation logic is shown below
loadComponent() {
this.currentAdIndex = (this.currentAdIndex + 1) % this.ads.length;
const adItem = this.ads[this.currentAdIndex];
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(adItem.component);
const viewContainerRef = this.adHost.viewContainerRef;
viewContainerRef.clear();
const componentRef = viewContainerRef.createComponent<AdComponent>(componentFactory);
componentRef.instance.data = adItem.data;
}
Also read this article about how the component factories work in Ivy.
What is the best practice way to define static class private properties in JavaScript ES6 in Node.js?
I have the following Log class:
'use strict';
const moment = require('moment');
const LOG_DATE_FORMAT = 'YYYY-MM-DDTHH:mm:ss.SSSZ';
module.exports = class {
static debug(txt) {
console.log(`${moment().utc().format(LOG_DATE_FORMAT)} [debug] ${txt}`);
}
static info(txt) {
console.info(`${moment().utc().format(LOG_DATE_FORMAT)} [info] ${txt}`);
}
static warn(txt) {
console.warn(`${moment().utc().format(LOG_DATE_FORMAT)} [warn] ${txt}`);
}
static error(txt) {
console.error(`${moment().utc().format(LOG_DATE_FORMAT)} [error] ${txt}`);
}
};
Is defining moment and DATE_FORMAT outside of the module.exports and thus class definition the correct way of doing this?
Yes, it's an acceptable way of doing things. Since you want to define some variables that you share among all your static methods, you have basically four choices:
Define them as statics on the class also so you can reference them using the class name as a prefix. This has the benefit or drawback (depending upon what you want) that it makes them publicly accessible on your exported class.
Define them as module level variables as you've done. This makes them accessible by all the static methods, but keeps their use private to your module.
Redefine them separately inside of each method.
Define them as globals.
Option #3 seems like a lot of repetition and certainly wouldn't be very DRY.
Option #4 does not seem like a good way to go since there's no reason to make these globals (you pretty much never want to use globals with node.js anyway).
So, it comes down to option #1 or #2 and which to choose totally depends upon whether you want their values to be accessible outside the module or not. If you want them exported also, then make them static properties on your class and refer to them with the class prefix. If you only want to use them inside the module, then what you have done is perfect.
In some frameworks like Angular, you can inject services and controllers into one other like this
App.controller('exampleController', function($scope, ajaxService){
ajaxService.getData().then(function(data) {
//do something with the data
});
});
This is called Dependency Injection according to Angular docs
You can do something like this in Slim Framwork too, like this
$app->get('/example', function() use ($app, $db) {
$data = $db->getData();
//do something with the data
}
This is called Currying according to Slim docs.
As far as I see these are the exact same thing? Why are they called by different names?
Couple of interesting reading here: What is currying
What is dependency injection
No matter the programming language or framework, we could say "Dependency Injection" (DI) is something like
delegation at OOP Class definition (see example) and Currying is something totally different, let's say function parameter simplification.
DI allows you keep your classes simple and de-coupled. If you are familiar with Laravel, ServiceProvider are a good example. In a nutshell your class has a property which will be set to a instance of another Class (normally implementing an interface) so that you can delegate some functionality. Typical example is:
interface LogInterface {
public function write();
}
class LogToFile implements LogInterface {
public function write()
{
//Do something
}
}
class LogToFileDB implements LogInterface {
public function write()
{
//Do something
}
}
class MyDIClass {
private $log;
public function __construct(LogInterface $log){
$this->log = $log;
}
public function writeLog(){
$this->log->write();
}
}
//You can do
$myobj = new MyDIClass(new LogToFile);
//or you can do
//$myobj = new MyDIClass(new LogToDB);
//this will work, no worries about "write()" you are delegating through DI
$myobj->writeLog();
I've just written this code above (probably not functional) to illustrate DI. Using the interface you ensure the method "write()" will be implemented in any class implementing LogInterface. Then your class forces to get a LogInterface object when objects are instantiated. Forget how "write()" works, it is not your business.
In regards Currying, technique is diferent you just simplify the params in a function. When using Slim Framework the guys says "you can curry your routes by using $app". I've used Slim a lot and my understanding in that way is, ok, rathaer than pass several variables to your route closures just enrich your $app variable and pass 1 single var: $app
$app = new \Slim\Slim();
//Rather than
//$app->get('/foo', function () use ($app, $log, $store, ...) {
$app->get('/foo', function () use ($app) {
$app->render('foo.php'); // <-- SUCCESS
$app->log->write();
$app->db->store();
});
So I'm writing a whole bunch of vendor-specific files in node which all have a similar controller pattern, so it makes sense for me to cut them out and put into a common file.
You can see my common controller file here: https://gist.github.com/081a04073656bf28f46b
Now when I use them in my multiple modules, each consecutively loaded module is overwriting the first. This is because the file is only required once and passed dynamically through to each module on load (this allows me to add extra modules and these modules are able to add their own routes, for example). You can see an example module here: https://gist.github.com/2382bf93298e0fc58599
You can see here on line 53 I've realised that we need to create a seperate instance every time, so I've tried to create a new instance by copying the standardControllers object into a new object, then initialising the new object. This has zero impact on the code, and the code behaves in exactly the same way.
Any ideas guys? I'm in a bit of a jam with this one!
First thing I'd do is try to make things simpler and reduce coupling by invoking the single responsibility principle, et al.
http://www.codinghorror.com/blog/2007/03/curlys-law-do-one-thing.html
Put those Schemas into their own files, eg
models/client.js
models/assistant.js
models/contact.js
I've also found that embedded docs + mongoose is generally a PITA. I'd probably promote all those to top level docs.
You don't need to enclose your object's keys in quotes.
routes = {
list: function() {} // no quotes is aok
}
Also 'list' in typical REST apps is called 'index'. Anyway.
Ok, I'd break this up differently. Since you're requiring stuff from the index.js file in the middleware, they become tightly coupled, which is bad. in fact, I think I'd rewrite this whole thing so it was tidier. Sorry.
I'd probably replace your 'middleware' file with an express-resource controller
https://github.com/visionmedia/express-resource (built by author of express). This is a good framework for restful controllers, such as what you're building. The auto-loader is really sweet.
You may also want to look at: http://mcavage.github.com/node-restify/ It's new, I haven't tried it out, but I've heard good things.
Since what you're building is basically an automated mongoose-crud system, with optional overriding, I'd create an express-resource controller as your base
/controllers/base_controller.js
and it might look like
var BaseController = function() {} // BaseController constructor
BaseController.prototype.index = function() {
// copy from your middleware
}
BaseController.prototype.show = function() {
// copy from your middleware
}
BaseController.prototype.create = function() {
// copy from your middleware
}
// etc
module.exports = BaseController
Then I'd do something like:
/controllers/some_resource_controller.js
which might look something like:
var BaseController = require('./base_controller')
var NewResourceController = function() {
// Apply BaseController constructor (i.e. call super())
BaseController.apply(this, arguments)
}
NewResourceController.prototype = new Base()
NewResourceController.prototype.create = function() {
// custom create method goes here
}
module.exports = NewResourceController
Then to use it, you can do:
var user = app.resource(myResourceName, new ResourceController());
…inside some loop which sets myResourceName to be whatever crud you're trying to set up.
Here's some links for you to read:
http://tobyho.com/2011/11/11/js-object-inheritance/
http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/
Also, it sounds like you're not writing tests. Write tests.
http://www.codinghorror.com/blog/2006/07/i-pity-the-fool-who-doesnt-write-unit-tests.html