I am using AngularJS for a SPA, and I am using browserify to build my application. Now the question came up whether we should write Angular services in the classical way, or simply require them.
As Angular services are singletons, this could be easily done with require as well: Simply expose an object literal, and you're done. Factories are also possible, simply expose a function. And so on ...
The only disadvantage I can currently think of is that I am not able to access other real Angular services from such a file (like, e.g., $http), but with browserify in the background this does not seem to be that important. E.g., you could easily use Node.js's http module for that, thanks to browserify.
So what do you think of this? What are other advantages and disadvantages for this?
PS: Please note that I'm not asking for whether this is good or bad, as this is probably mainly subjective. I'm rather interested which opportunities appear, or which risks I have to deal with.
One disadvantage to doing this is writing unit tests. It will be difficult to mock your dependencies if you are simply requiring them rather than using Angular's dependency injection.
This is somewhat of a dealbreaker for me because one of the many benefits of using Angular is the testability of the framework.
It's bad.
Just use browserify to initially load in all the modules you need.
you miss out on $httpBackend
your code becomes harder to follow, ie, there is very rarely a point to reuse that directives controller
you miss out on $http interceptors
you miss it in being able to modify and interact with other injectables.
The only thing I'd use browserify/webpack/requirejs for in an angular app is two things:
creating js bundle
injecting templates as strings into the angular template cache as a module.
Personally this kind of approach is just a pointless complication.
If you require things like $http you won't have any way to inject dummy/mocks of those services during testing.
Although somewhere you will do the wiring between your super-duper service that needs $http and the place you need it.
The first thing that came into my mind is resolvers in routes. You can even have some helper methods to deal with declaring the same dependencies many times.
Imagine this module:
function SuperResource($http, pathExpression) {}
exports.SuperResource = SuperResource;
exports.superResourceFactory = function(pathExpression) {
return [
'$http',
function() {
return new SuperResource($http, pathExpression);
}];
};
Somewhere you will do:
var myModule = require('./myModule.js');
resolvers: {
usersResource: myModule.superResourceFactory('/users')
}
Or even you could have a user modules that defines the user resource:
var myModule = require('./myModule');
exports.userFactory = ['$http', function() {
return new myModule.SuperResource($http, pathExpression);
}
Yes, these are angular specific helpers in an otherwise angular free code, but at least they're isolated in their own method/name.
Related
I was wondering what should be considered when creating Angular services in regards to which module to attach the services too.
For example
var app = angular.module('app', []);
//Add service to app module
app.factory('helloWorld', function() {
return {};
});
//Or create a module for the service, and include the module where needed
var helloWorldModule = angular.module('helloWorldModule', []);
helloWorldModule.factory('helloWorld', function() {
return {};
});
//Or attach is to an existing module that may need it
existingModule.factory('helloWorld', function() {
return {};
});
Should all services created be added to the app module, so I can ensure that I can access the service anywhere if I need to, or should I add it to only the modules that I know that will be using it.
I know that this may be subjective, and based on application structure, basically I am just wondering if it is ever a good idea to add all services to the app module.
As always it depends. If your service is an isolated service that can be shared across different applications and modules then the answer is yes.
If it is relevant only to your current module then no.
Try to maximise the cohesion. If you only have a solution or app it doesn't matter where you place the service, but if you have multiple solutions, maybe during a refactoring process you realise that some services make sense to put them together in the same module.
Let's start with some reference code
var express = require('express');
var app = express();
var session = require('express-session');
app.use(session({
store: require('connect-session-knex')()
}));
I have a couple questions here that I would like to answer in case you know the answer:
Everytime a require is call in Nodejs, is that named dependency injection? Or what is the real meaning of dependency injection?
The reason why I am asking this, is because I've been reading about Node, and I see people people talking about the module or module.export pattern, and I am confuse, the module is the same as dependency?
So, all I need is a clear explanation about dependency injection, and when/where you need to inject a dependency . . .
Dependency injection is somewhat the opposite of normal module design. In normal module design, a module uses require() to load in all the other modules that it needs with the goal of making it simple for the caller to use your module. The caller can just require() in your module and your module will load all the other things it needs.
With dependency injection, rather than the module loading the things it needs, the caller is required to pass in things (usually objects) that the module needs. This can make certain types of testing easier and it can make mocking certain things for testing purposes easier.
Everytime a require is call in Nodejs, is that named dependency
injection? Or what is the real meaning of dependency injection?
No. When a module does a require() to load it's own dependencies that is not dependency injection.
The reason why I am asking this, is because I've been reading about
Node, and I see people people talking about the module or
module.export pattern, and I am confuse, the module is the same as
dependency?
A module is not the same as a dependency. Normal module design allows you to require() just the module and get back a series of exports that you can use. The module itself handles the loading of its own dependencies (usually using require() internal to the module).
Here are a couple of articles that discuss some of the pros/cons of using dependency injection. As best I can tell the main advantage is to simplify unit testing by allowing dependent objects (like databases) to be more easily mocked.
When to use Dependency Injection
When is it not appropriate to use dependency injection
Why should we use dependency injection
A classic case for using a dependency injection is when a module depends upon a database interface. If the module loads it's own database, then that module is essentially hard-wired to that particular database. There is no architecture built into the module for the caller to specify what type of storage should be used.
If, however, the module is set up so that when a caller loads and initializes the module, it must pass in an object that implements a specific database API, then the caller is free to decide what type of database should be used. Any database that meets the contract of the API can be used. But, the burden is on the caller to pick and load a specific database. There can also be hybrid circumstances where a module has a built-in database that will be used by default, but the caller can supply their own object that will be used instead if it is provided in the module constructor or module initialization.
Imagine this code.
var someModule = require('pathToSomeModule');
someModule();
Here, we DEPEND not on the name, but on the path of that file. We are also using the SAME file every time.
Let's look at angular's way (for the client, i know, bear with me)
app.controller('someCtrl', function($scope) {
$scope.foo = 'bar';
});
I know client side js doesn't have file imports / exports, but it's the underlying concept that you should look at. Nowhere does this controller specify WHAT the $scope variable ACTUALLY is, it just knows that angular is giving it something CALLED $scope.
This is Inversion of Control
It is like saying, Don't call me, I'll call you
Now let's implement our original code with something like a service container (there are many different solutions to this, containers are not the only option)
// The only require statement
var container = require('pathToContainer')
var someModule = container.resolve('someModule');
someModule();
What did we accomplish here? Now, we only have to know ONE thing, the container (or whatever abstraction you choose). We have no idea what someModule actually is, or where it's source file is, just that it's what we got from the container. The benefit of this is that, if we want to use a different implementation of someModule, as long as it conforms to the same API as the orignal, we can just replace it ONE place in our ENTIRE app. The container. Now every module that calls someModule will get the new implementation. The idea is that when you make a module, you define the api that you use to interact with it. If different implementations all conform to a single api (or you write an adapter that conforms to it) then you can swap out implementations like dirty underwear and your app will just WORK.
This approach is not for everyone, and some people hate lugging around the container.
My personal opinion, I would rather code to an interface ( a consistent api between implentations ) than code to a concrete implementation.
An actual example of Dependency Injection in node.js
// In a file, far, far, away
module.exports = function(dependencyA, dependencyB) {
dependencyA();
dependencyB();
}
// In another file, the `caller`
// This is where the actual, concrete implementation is stored
var depA = someConcreteImplementation;
var depB = someOtherConcreteImplementation;
var someModule = require('pathToSomeModule');
someModule(depA, depB);
The downside to this, is now the caller needs to know what your dependencies are. Some are comforted by this and like it, others believe it's a hassle.
I prefer this next approach, personally.
If you aren't using babel, or something that changes your functions behind the scenes, you can use this approach to get the angular-style parameter-parsing
http://krasimirtsonev.com/blog/article/Dependency-injection-in-JavaScript
Then you can parse the function you get from require, and not use a container at all.
I use injection-js Dependency injection library for JavaScript and TypeScript with ts-node:
npm i -P injection-js
It's based on the angular2 injector so Injection is super simple.
Here is the typescript version from the README.
import 'reflect-metadata';
import { ReflectiveInjector, Injectable, Injector } from 'injection-js';
class Http {}
#Injectable()
class Service {
constructor(private http: Http) {}
}
#Injectable()
class Service2 {
constructor(private injector: Injector) {}
getService(): void {
console.log(this.injector.get(Service) instanceof Service);
}
createChildInjector(): void {
const childInjector = ReflectiveInjector.resolveAndCreate([
Service
], this.injector);
}
}
const injector = ReflectiveInjector.resolveAndCreate([
Service,
Http
]);
console.log(injector.get(Service) instanceof Service);
I like keeping my javascript files as small as possible and using an architectural pattern. This usually means splitting my js files in Services, Controllers, Models, Views, etc.
Meteor automatically loads all js files. However every variable defined in any js file is processed as a local variable for that file. To be able to access them I have to define them like so:
//global
my_global_function = function(){
}
//not global
var my_global_function = function(){
}
//not global
function my_global_function(){
}
Defining a variable/function without the keyword var or function is not good practice. What are the possible alternatives?
The best option is to use ES2015 modules.
Meteor does not support modules natively yet, but there are packages that bring this support.
For example, universe:modules.
With modules you can import and export some variables/functions/classes/etc:
// module1.import.js
import alertSomething from './module2'
Meteor.startup(() => {
alertSomething();
});
// module2.import.js
export default function alertSomething() {
alert('something');
}
universe:modules is not the only solution, there are other similar projects. I love this one specially https://github.com/thereactivestack/kickstart-simple. It replaces Meteor's build system with WebPack's and enables hot-reloading if you use React.
UPDATE:
Meteor does support ES6 modules now
Since you seem very interested in proper architectural design, I would recommend looking at Meteor packages. Essentially, you have to declare any globally exposed variable in the package.js configuration, which is what you want: as little "leakage" as possible. Within a package, you can afford to be a little bit more sloppy, but you can still use var (and the absence of var) for more fine-grained control within a package. This can be done within Meteor right now.
You can find most information in the package documentation. The easiest way to get started is to create a package using meteor create --package [package-name]. This sets up a basic structure to play with. The api.export function is what controls exposed variables. See doc here.
Additionally, be careful with adding an unnecessary layer on top of the intrinsic Meteor architectural design. Templates are views, server side methods are services, etc. There are only some things that you don't get out of the box, so usually you'll add something like Astronomy or SimpleSchema.
Adding too much of your own architecture is probably going to end with you fighting the Meteor framework itself...
I'm planning out an application that ideally I'd like to keep decoupled from Angular, so all the dom interaction will go into an Angular layer but the core business logic will be kept in a standalone app that is totally unaware of Angular. The two will communicate via Angular services that are able to send messages to the core application.
The standalone app will most likely use requirejs to handle dependency injection.
What I'm unsure of is how to get a module that may be declared something like this:
define('AppInteractor', ['require'], function(requre){
// Set up interactor functionality
});
Into an Angular service.
My first though was to have some kind of adapter like this:
define(['AppInteractor', 'angular'], function(interactor, angular) {
var app = angular.module('appInteractor', []).service('AppInteractor', interactor);
});
This would register the AppInteractor as a service within an angular module, the problem with this approach seems to be that because requirejs loads things asynchronously the service hasn't been set when the angular code runs. It also seems to end up with angular loading twice which presumably also doesn't help matters.
I've seen a few articles covering loading all Angular components via require but I was hoping there might be simpler way to make this work.
Can anyone recommend how I might make this work?
If you are going to add a service after the main modules initialization, I recommend you add it to your application module
define(['AppInteractor', 'angular'], function(interactor, angular) {
// There is no second parameter, because we are getting an existing
// module, not creating a new one.
var app = angular.module('appModule');
app.service('AppInteractor', interactor);
});
Otherwise, if you want to group all your other logic in a different module, you will need to import the module and add it as a requirement of your application module.
define(['AppInteractorModule', 'angular'], function(interactorModule, angular) {
var app = angular.module('appModule', [interactorModule.name]);
});
I also recommend you use a tool like ES6 (6to5, traceur), browserify or Typescript for your module management, and then compile to AMD. I find it easier and cleaner for development.
I'm learning AngularJS and in all tutorials and screencasts I always saw to use angular writing code all in a unique file, example directives, controllers, factories etc...
Logically for large applications, you will split out the code, make it maintainable and flexible in multiple files and also we should be careful about how many <script> tags we have to require to let our JavaScript files run correctly.
I would like to know which is the best practice to require files when needed, importing less javascript files possible in my view. I took a look at RequireJs but it seems a bit complicated to use it. Is there some tool more efficient and easy to use? Or any good resource to get started?
A small example can be that I have a sort of plugin that has been built using directives, controllers and factories:
app-|
--Controllers
|_ pluginController.js
--Directives
|_ pluginDirective.js
--Factories
|_ pluginFactory.js
Instead of requiring all three files how do you make it work?
Here' a great example of how to use RequireJS and AngularJS together. It's a fork of the Angular Seed project and it should hopefully point you in the right direction. It comes with RequireJS baked right in. I definitely recommend learning RequireJS!
I would advice you to read up on dependency injection in the Angular documentaion. It all depends on how you set things up to be honest. If you want to use your service/factory in your controller then you would add the factory as a dependency in your controller or directive. See example below :
Angular.module('{YOUR MODULE NAME}').controller('{YOUR CONTORLLER NAME}', ['$scope', '{FACTORY NAME}',
function($scope,{FACTORY NAME}) {
}]
To invoke the directive within your controller, you would simply could simple add the directive to your controller template. This is a basic example, to learn more read about dependancy injectioninvoke
To be clear that I understand - e.g. I want to use "angularFileUpload" module, I need to add it to my module dependency list -
angular
.module('kids', ['angularFileUpload'
])
and load the script?
<script src="angularjs/plugins/angular-file-upload/angular-file-upload.min.js" type="text/javascript"></script>
Thanks for help.