How should I make configurable modules in AngularJS - javascript

I've been tinkering with AngularJS and I've built up a small collection of directives and services that I would like to package into a single JS file so that I can use them anywhere.
I have some website specific settings that my module will need for API calls and that sort of thing. I'm just wondering what the Angular way of making configurable modules is. Obviously I don't want to have to modify my reusable JS file for each website, as that kind of defeats the purpose of having it. Seeing as the values are going to remain the same for each website it seems like an awful lot of hassle to pass them in as an argument on each function call, and I'd rather stay away from global variables as much as possible.
I've searched a lot of questions for the answers I seek, and the closest pattern I've found so far is to have my reusable module be dependant on a not included module called "settings" or something and then define that module in the page's JS file, allowing the reusable module to pull the values from it. Here's an example to show what I mean.
This seems backwards to me. It's kind of like having a function pull values from global values instead of passing the values in as arguments.
Is this really the best way of doing this, or is there an alternative?

It sounds like you're looking for a provider.
You should use the Provider recipe only when you want to expose an API for application-wide configuration that must be made before the application starts. This is usually interesting only for reusable services whose behavior might need to vary slightly between applications.
Here's a very basic example of a provider:
myMod.provider('greeting', function() {
var text = 'Hello, ';
this.setText = function(value) {
text = value;
};
this.$get = function() {
return function(name) {
alert(text + name);
};
};
});
This creates a new service, just like you might with myMod.service or myMod.factory, but provides an additional API that is available at config time—namely, a setText method. You can get access to the provider in config blocks:
myMod.config(function(greetingProvider) {
greetingProvider.setText("Howdy there, ");
});
Now, when we inject the greeting service, Angular will call the provider's $get method (injecting any services it asks for in its parameters) and gives you whatever it returns; in this case, $get returns a function that, when called with a name, will alert the name with whatever we've set with setText:
myMod.run(function(greeting) {
greeting('Ford Prefect');
});
// Alerts: "Howdy there, Ford Prefect"
This is exactly how other providers, like $httpProvider and $routeProvider work.
For more information on providers and dependency injection in general, check out this SO question on dependency injection.

Related

Best practice to change default blueprint actions in sails.js

I'm looking for an answer to what is the best practice to customize default sails.js CRUD blueprints. The simple example of what I mean is let's say I need to create SomeModel, using standard blueprint POST \someModel action, and also I want to get information about authenticated user from req object and set this property to req.body to use values.user.id in beforeCreate function:
module.exports = {
attributes: {
// some attributes
},
beforeCreate: function (values, cb) {
// do something with values.user.id
}
};
I'm very new to sails.js and don't want to use anti-patterns, so I'm asking for inputs on what is the right way to handle such cases. Also it would be great to have some good resources on that topic.
There are a few options open to you which you've identified, and as usual, it depends on your use case. Here are some thoughts on the three options you listed in your comment:
Override controller/create - Of the three, this is the best option because it doesn't clog up code in routes or policies for a single instance.
Write controller/action and add to config/routes.js - While this works, it defeats the purpose of using blueprints, and you have to do all the code in option 1 plus making your routes code messier.
Apply a policy for a single create action - To do this, you will not only have to clutter up your /policies folder but also your policies.js file. This is more code AND it puts the logic for one controller method in two separate places, neither of which is the controller.
Out of these three, option 1 is the best because it contains the code to its context (the controller) and minimizes written code. This is assuming that you only want to alter the create method for one model.
Side note:
As an example of how your use case determines your implementation, here is how I've set my Sails app up which has a few REST routes, each of which responds differently based on the user calling the route (with a valid Facebook token):
Only uses blueprint action routes (not blueprint REST routes)
First goes through the policies:
'*': ['hasFBToken', 'isTokenForMyApp', 'extractFBUser', 'extractMyAppUser'] which store fbuser, myappuser, and other variables in req.body
At this point, my controller function (e.g. controller.action()) is called and can access information about that user and determine if it has the correct permissions to do CRUD.
Pros of this system:
All code for each CRUD operation is contained within its controller function
Minimal to no code in routes.js (no code) or policies.js (one line) or /policies
Works well with API Versioning (e.g. controllers/v1.0/controller.js), which is much easier to do with versioned controllers than versioned models. That means that I can create a new API version and simply by creating a controller in /v2.0 with a function action(), calls such as POST /v2.0/controller/action will exist with no extra routing needed.
Hopefully this example helps illustrate how design decisions were made to offer functionality like API versioning and consolidate code in its specific context.

AngularJs defining global variables

What is the best way to define a global varible in AngularJS?
I know there are plenty of solutions about this topic, the most commom:
Use a service;
Use $rootScope;
I want an answer for a different context. For example:
A commom url used for multiple requests in multiple services: my/folder/class.php;
The name of a main module: myApp;
A commom alert message for an error: Failed to connect to the server, try again.
Things that will be used all over the app, in different situations and will never change.
Looking around the internet I saw 2 other possibilities other then $rootScope and services:
Use AngularJS constants;
Use JS var outside of the main ng module;
So my question is: For the AngularJs scenario, what is the best alternative?
Do we really use constants for this situation? Is there any other provider for this purpose. Also I'd like to know whats the performance impact of the, if any.
For true constants use Angular constants. If your values may need to be configured or calculated use an Angular service and expose getter functions. For strings you may want to consider localization, so use one of the Angular localization libraries to store these (I use Angular-localize).
Hope this is helpful.

Why do Services, Constants, Etc Need to be Injected?

Let's say I create an AngularJs service. I attach it to my module:
angular.module('fooModule').service('myService', function(){
var service = {
logSomething: function() {
console.log('Service logged something');
}
};
return service;
});
Whatever. It's there - same with constants, factories, providers, etc. Why do I need to then inject this service, constant, etc into my controllers? Is it essentially the same principle as "using" in C# - the only purpose being avoiding conflicting variable/function names? That doesn't seem to make sense since I still have to write myService.logSomething() which clears up the whole namespace issue.
Or does it somehow speed up loading? I don't see how that would be though.
You haven't actually injected this service into anything yet; it is just a singleton at this point. You have registered it with your angular module, yes, but nothing else in your module knows about it. It's not available until you actually inject it. In a very abstract way, you could think about dependency injection in Angular like using or import, but it's really more like supplying an initializing variable in a constructor (actually, this is exactly what it is).
If you are wondering why dependency injection might be a good design practice in general, this post should be of interest to you.

knockoutjs in nodejs using .fn extensions in custom modules?

I am looking at trying to get the knockout.mapping.merge library working in node, however I am unable to work out how to achieve extension of ko objects within the module scope as I am unable to extend the underlying ko instance.
So for example in my module I am exporting all the methods relating to the mapping.merge logic, however there is also some logic which extends the base observables to give them the ability to register their merge preferences:
knockout.observable.fn.withMergeMethod = function(method) {
this.mergeMethod = method;
return this;
}
knockout in the above scope would be the result from require("knockout"); but that scope only matches this. I was thinking I could possibly have some sort of init method which passes in the knockout constructor to enrich it in a node environment but was wondering if there was a better solution?
it seems like nodejs require only has one instance of the given dependency so if you update it in other defines it will apply those changes to all objects using that require:
Modules initialization in node.js and persisting their state between requests
Or so says this question, although I am not sure if that is a nice way to go in node, so will wait and see if there are any better answers.

Angular.js and DAO pattern

First of all I must admit I am quite new to Angular.js and I haven't used any new generation js framework like Backbone or Knockout before. I'm creating an application which communicates with server using RESTful API. I dug a lot into angular documentation and blog notes so as I could do it right.
I found examples mostly with $resource. It looks pretty good: many built-in methods, when you design your REST interface properly you don't even have to write anything more.
But I (and my whole team too) are more used to JavaEE way of thinking about model layer: lightweight model classes (POJO, etc), DAO classes persisting and fetching model and optionally service layer between DAO and controllers. On the other hand in Angular $resource creates something more resembling active record.
I've already come up with two ways how to implement DAO pattern in Angular:
Writing everything from scratch, going down to the $http abstraction level. I'd implement every DAO method as $http call, take care about errors.
Using $resource objects normally like lightweight model classes and passing them to DAOs which are the only unit responsible for calling actions like .$save() on them. Of course we cannot prevent calling it in different place, but solution with such convention is good enough for me.
Second way looks better for me because of reusing existing code. $resource has nice behaviour of promise object and I will be happy if I don't have to implement it myself.
So finally the main question: is active record approach is the only way of doing data access right in Angular, Backbone and other tools like that? Maybe somebody have already tried to incorporate similar solution more resembling DAO in his code and can share his thoughts about it?
And the second question: is $resource object sufficient when it comes to dealing with errors, connection losses and different problems? Is it worth to use $resource having this in mind or it's better to start with lower level $http.
I am at the beginning of the project and I know that this decision may well affect the whole project life later, so I want to choose the best.
I totally agree. Here is the way I do it:
bankApp.factory("CustomerRepository", function ($resource) {
var customerRepository = $resource("rest/customers/:id", {id:'#id'}, {'update': {method:'PUT'}});
// You can also add addition repository like $http calls onto the
// customerRepository like getting the count and other stuff.
return customerRepository;
});
Then you can inject the CustomerRepository where ever you need it. For example:
bankApp.controller("BankController", function ($scope, CustomerRepository) {
$scope.customers = CustomerRepository.query();
$scope.createCustomer = function () {
CustomerRepository.save($scope.customer, function (customer) {
...
});
};
...
$scope.saveCustomer = function () {
CustomerRepository.update($scope.customer, function (customer) {
...
});
};
});

Categories