Design pattern for sitewide configuration in Angular JS - javascript

I want to set some user preferences in my angular app. I will get these preference from a REST api so I will need to make a http call. Once these have been fetched from the API, their values will not be modified.
What is the best practice in this case?
Can I make http calls in angular.module.value? Or use something like a provider? Or just write a service? What are the things to consider in any of these approaches?
What is the design pattern to be followed in this case?

You could create a service using the factory recipe. That will make the code a lttle cleaner and more modular.
Following that, you could put the user preferences on the $rootScope. This is a good case for a valid use of $rootScope, since your values are constants with application-wide applicability.

Related

Passing $scope to angularJs service/factory a bad idea?

I am working on a project where in there are almost 90+ modules.
All modules has a set of input fields and on submit the data should be saved on the server.
At any given point in time only one module is active. But there can be open modules in the background.
Submit button is common to all modules, meaning there is only one Submit button throughout the application.
Below picture explains it more.
The prime motto is to keep the individual module changes to minimum and a way to handle certain things(validation, reload etc) in the module from a central place.
The current approach I am planning is,
Use a 'moduleInit' directive that all module should include in its
partial.
The directive takes the $scope of the module and pass it to a
common service/factory (pushConfigService)
The pushConfigService stores and keep this scope as long as the
module is open. Once the scope is destroyed the reference of the
same will be removed from the pushConfigService.
The footer panel is another directive with Submit button in it and
calls a save function in the pushConfigService which in turn calls
a $scope function in the module to get the form data.
pushConfigService talks to a bunch of other services like
dirtyChecker, apiGenerator and finally post data to the server.
Each module will have a set of scope methods defined with some standard names. Eg: _submit, _onSubmit, _cancel, _reload etc.
Another way to handle this, broadcast the submit event and each module listens to the same. There is possibility more actions will be added to the footer panel.
So I am little bit hesitant to use the broadcast approach.
My question, Is it a good idea to pass controller scope to a service? Any alternate suggestions?
Thanks in advance.
I believe your core concept is a nice way to handle this setup. Yet I'd suggest to split business logic from UI. I don't have a sample of your code so it is a little hard to build an exact example. Yet since you're using the $scope variable I'm going to assume you're not using a styleguide like or similar to John Papa's. His ways encourage you to not use the $scope and to stay close to actual JavaScript "classes".
How does this make a difference?
Instead of passing the whole scope, you'd be able to just pass the instance of your specific module. For one it is less confusing to you and colleagues to have a concrete interface to operate on instead of having to figure out the composition of given scope. In addition it prevents services from being able to alter the $scope.
The latter could be considered a good practice. Having just the controllers alter the scope make it easy to find the code which alters and manages the UI. From there on the controller could access services to do the actual logic.
Taking it one step further
So passing the class instance instead of scope should be an easy adjustment to the already proposed setup. But please consider the following setup as well.
It seems there are quite some different ways to handle and process the data provided by the module/end user. This logic is now implemented in the controller. One might think some of these modules share similar handling methods (big assumption there). You could move this logic to, so to speak, saving strategies, in services. On activation of a module, this module will set its preferred saving strategy in the service which handles the submit button click. Or more precisely, the save data method which should be called from the onClick handler in the controller.
Now these services/strategies might be shared among controllers, potentially setting up for a better workflow and less duplicated code.

Where I should keep data using AngularJS?

I've got a question about storing data in AngularJS. Should I use some kind of service, or controller to keep data? I saw different codes in Angular and one time people store data in service, other, in controller. I would say that the proper way is to keep it inside factory, but is it a good practice?
Thanks!
Well, it depends on what you mean "storing data" for you...
If you mean keeping data in some place just for passing it between controllers, then this place is a service.
If you mean keeping data so it can persist even after a page refresh or after closing the browser and reopening the same app then you can use the javascript apis for sessionStorage and localStorage (take into account that older browsers may not have these apis and you would have to polyfill them). I've used an angular service for this that have given good results: https://github.com/tymondesigns/angular-locker.
If you mean persist the data for using it among other systems different than yours, the you should rely on a database server, either yours or from a third party (take a look at Firebird).
Of course you have more options, but they don't differ from the ones you have if you use plain javascript. Each of them could be treated in an "Angular way" if you create a service to manage them (IndexedDB, WebSQL, etc.) In the end it depends on what you're trying to achive.
If you need to use the data across multiple views / controllers, for example a logged in user, then i would recommend a service which holds the data for you. This way you can access it from anywhere you inject it. However, if you need your data only in one of your controllers, i dont see a reason to create a service, just store it in the controller.

Angular.js Method duplication in controller when using service

I've created a BookService that is used for storing (add), getting (getAll) and removing (remove) books. Now I want to use this BookService inside my controller to publish some methods that I can later use in my view. My controller looks like the following:
app.controller('BookController', ['BookService', '$scope', function(BookService, $scope) {
$scope.addBook = function() { BookService.add(); }
$scope.getAllBooks = function() { BookService.getAll(); }
$scope.removeBook = function() { BookService.remove(); }
}]);
As you can see, the controller is just a proxy that forwards the method calls to the service. Is this in general bad practice? And is there a better way to solve that using Angular.js? Calling the service directly from the view without a controller seems, to me like a bigger problem.
Best Practice
From what I can see this is perfectly good practice, I'm assuming that you're using $scope here to bind these services to a button or something similar. The Idea of using a factory or a service is to create some well organised reusable code that you can then instantiate in your controller exactly like you have done.
Controllers can get quite complex so moving basic functionality to your service is the best thing to do. In your case you have a relatively simple controller so you may not see the benefit of coding in this way. But I assure you that as your code base grows you will be required to code like this just to keep things readable.
Note
Just as an extra note I've added a data process that you might take with an example of a database request
database > API > service/factory > controller > view
This would be the correct path to take when requesting something from a database.
What you have shown is not bad practice; it is in fact recommended that you abstract resource management logic (like adding, removing and finding resources of the same type) into a separate service, for organization and maintainability and reusability purposes.
I do understand from your example how the controller seems to be just a proxy to the service though, and why you would think it's repetitive and possibly redundant. Let me expand on your example to see if I can explain the reasons for abstracting the logic. In doing so, let's consider only the adding operation, even though the logic would apply to others as well.
Reason 1: adding a book (or any resource for that matter) in a web app is usually more complicated than just a bookService.add() call. It requires having some sort of form to enter the details, a submit button to handle the actual request, possible massaging of the entered data, adding new fields like time stamps and author ids, and persisting to some data storage. The first two or three of those steps would be applicable to the screen or view from which you are adding, so it makes sense to put that in a controller (the view model), whereas the rest of the steps should go into the generic service.
Now say you have another screen where you see a friend's list of books and you can add it to your list by selecting a book. In that case, the controller logic for that view's controller will differ from the previous example, but the service steps will still be identical, and thus do not need to be duplicated since the service can be injected into both controllers.
That's a big win.
Example 2: let's say you've already split the code between controller and service as describe in example 1 above. Then you decide that your data storage needs have changed and now you want to update your logic to save to a different database system. Now instead of having to change all the controllers, you just change your services and the everything works.
This is also a really big win.
Yes you'ved done this correctly. Just keep in mind that as you scaled up your app in complexity, you'll want to have isolated scopes, (and) decomposition into component directives. Each directive will have its own controller and template fragment.

Best way to handle configuration in AngularJS

Right now I have a service that runs and is injected into almost every single controller that provides a different API version string and URL string for requests based on $location's information as to whether the app runs on localhost or the website URL. Can something be set up to do something like this instead?
angular.module('app', [])
.config(['$location', function($location) {
// create app constants here and provide them globally somehow without requiring injection
// something like constants.api, module.constants.api, or pretty much anything
// else that exposes the keys set here in a developer-friendly way.
}]);
I am aware that $location isn't available in .config, so the above method won't completely work, but it's just food for thought.
I'm also open to any other suggestions on how to do all the configuration in AngularJS, because I haven't really found a good, clean way to specify app constants without having to use [insert build tool here] and create lots of constants and clutter my DI. I don't think AngularJS was intended to create such cluttered dependency management, but if I'm wrong, someone please correct me and explain a good way to set up better dependency management.

What are "decorators" and how are they used?

I'm curious what exactly decorators are in AngularJS. There isn't much information online for decorators save for a blurb in the AngularJS documentation and a brief (albeit interesting) mention in a youtube video.
As the Angular guys put it a decorator is:
Decoration of service, allows the decorator to intercept the service
instance creation. The returned instance may be the original instance,
or a new instance which delegates to the original instance.
I don't really know what that means, and I'm not sure why you would separate this logic from the service itself. For example if I wanted to return something different under different conditions I would just pass different arguments to the relevant functions or use another function sharing that private state.
I'm still kind of an AngularJS noob so I'm sure it's just ignorance and/or bad habits I've picked up.
A good use case of $provide.decorator is when you need to do minor "tweak" on some third-party/upstream service, on which your module depends, while leaving the service intact (because you are not the owner/maintainer of the service). Here is a demonstration on plunkr.
Decorators allow us to separate out cross-cutting concerns and allow services to preserve the single-responsibility-principle without worrying about "infrastructure" code.
Practical uses of decorators:
Caching: if we have a service which makes potentially expensive HTTP calls, we can wrap the service in a caching decorator which checks local storage before making the external call.
Debugging/Tracing: have a switch depending on your development/production configuration which decorates your services with debugging or tracing wrappers.
Throttling : wrap frequently triggered calls in a debouncing wrapper. Allows us to easily interact with rate-limited services, for example.
In all these cases, we limit the code in the service to its main responsibility.
decorator can intercept service instance created by factory, service, value, provider, and gives the options to change some instance(service) that is otherwise not configurable / with options.
It can also provide mock up instances for testing purpose, for example $http.
In simple word we can say that it’s like an extension method. For Ex. We have a class and it has two methods and at run time we want to add more method in it then we use Decorator.
We cannot use $provide.decorator with constants because we cannot change the constants they are heaving read only property.
In short decorators can be described as follows :-
A decorator function intercepts the creation of a service, allowing it
to override or modify the behavior of the service.
It uses the $provide service by angular and modify or replaces the implementation of another service
$provide.decorator('service to decorate',['$delegate', function($delegate) {
// $delegate - The original service instance,
// which can be replaced, monkey patched,
// configured, decorated or delegated to.
// ie here what is there in the 'service to decorate'
// This function will be invoked,
// when the service needs to be provided
// and should return the decorated service instance.
return $delegate;
}]);
Example:
$provide.decorator('$log', ['$delegate', function($delegate) {
// This will change implementation of log.war to log.error
$delegate.warn = $delegate.error;
return $delegate;
}]);
Applications
In addition to #JBland answer.
Application wide locale settings :-
You can find an example here
Changiging default behaviour of and existing implementation of a service by angular service :-
You can find an eample here
Switching behavior of a function in different environments.

Categories

Resources