Angular: How to go about refreshing service data - javascript

I am fairly new to Angular and trying to build an Angular application.
I have a lot of data that needs to be used by multiple controllers throughout the app. As I understand it, that is the perfect situation to use a service.
I am planning on storing this kind of data in services. For example I plan on having a users service which all controllers that need user data will inject.
I would like the users service to hold the master list of users and any controller that needs users to just use the one instance of service list.
I am having trouble envisioning the pattern though. I mean:
1) What is the standard way of having the service refresh its data from the server? I realize that I could just go and request the entire list of users every 10 seconds from the server but that seems kind of heavy weight...
2) Ideally I would like to be passing around only a single instance of each user. This way if it gets updated in the service, it is sure to be updated in all of the controllers. I guess the other option is to have the service broadcast an event every time it updates a user? or to use watchers?
3) What is the pattern by which the controllers interact with the service and filters? Do the controllers just request data from the service and filter it in the controller? The other option is to have the service do the filtering. If so how do I communicate the kind of filtering I need done to the service?
I think that by using some kind of solid pattern I can take care of alot of these issues (and more that I am sure will arise). Just looking for advice on some common patterns people employ when using singleton services.
Thanks in advance.

Answer to point 1. A service is just a singleton. How you store and refresh data into it has nothing to do with its nature. Not sure why you want all user data inside a service (unless you are building a user management app), but you could use several techniques like polling (eg. using $timeout ask for new users and append them to the existing ones) or push (eg. socket.io/signalR which will push you the payload of new users when available). This can be done both inside the service itself or by a controller that will add/remove data to the service (eg. a refresh users button in the UI)
Answer to point 2. You can bind/use the reference of the data inside the service directly into your controllers using a getter so that changes to the data are shown instantly (given that are two way binded, if not use events).
Answer to point 3. You can apply filters inside the controllers or in the view it self (not recommended). You can also have a function in the service where you pass the filter or filter params and get the filtered copy of the users collection back (since you will be using the users collection directly in many controllers at once you shouldn't modify that, unless that's desired). If you are reusing the same filters again and again across the controllers you can have a function for each filter that returns the filtered collection with a "hardcoded" filter. You can even have helper function in the service to help you assemble complex filters or have multiple copies of the collection already filtered cached(if you find you are using the same filter again and again)

Related

AngularJS transfer data between one component to another

Have some data for one controller JSON, I fill by this data in ng-repeat my view.
But when selecting this data from view I need pass selected data to Form Controller fill all forms.
I don't know how to do this in angularJS with components. I built service, which parse data when i select it and pass to Form Controller. But it's additional work parse it again by service.Maybe exist some more good way how pickup just id, and Form Controller load it automatically when get id's from service.
AngularJS really hard for all ways as I understood :(
It's better to provide some code samples with the question. Actually you have 3 main ways to share data between modules - parent controller, rootScope and services. Ok, there is event emitter here, but I heard opinions that it's not 'Angular way' to use events, because it's hard to maintain this architecture later. As I understood, you are using service for this porpoise and it's fine. Since Service is Singleton in Angular you can use it not only to share reusable peaces of code but and for sharing data between controllers.

AngularJS - accessing elements inside a controller from a service

I have an app with two controllers where I want a change in one controller to affect (different) data stored in the other. tl;dr when I remove a category from the first controller, I want to edit any items in the second controller with that category, so that they will now be category-less.
As far as I can tell what I want is to use a service, but I feel it would be simpler if there were a way for me to simply edit the data inside the controller scope. So my questions are:
Is there a way to simply edit controller data or call controller methods from a service?
Otherwise, is it reasonable to store the latter controller's data in the service, even though the former controller only needs access to change it? How do I reference this data for the purpose of doing ng-repeats?
Edit: to clarify the data is a set of json objects which contain data for each category and each item, and the web page contains ng-repeats to go through and list each of them. I have a number of functions which edit both lists of data, and I want changes to one list to make changes in the other.
Your idea was correct, you should put all your business logic, including data that needs to be consistent between different parts of your application, into services. controllers should only manage the view and connect the data to it.
Keep in mind that services are Singletons - there is always only one instance of each service, holding your data.
To answer your question: I would argue that storing data in a service instead of a controller is always reasonable when it works (aka when the data is not specific to one of multiple views, but consistent throughout the current application state), and giving access to that data to manipulate it is perfectly fine - even better would be to put the manipulation logic into the service itself (or another service only for that) and to just let the controller connect to a call invoking that.
There is an article by Todd Motto on that topic (thin controllers)
I think it will be better use events for this purpose. In your first controller you can published the event on category deletion like below.
$scope.deleteCategory = function (category) {
$rootScope.$broadcast("categoryDeleted", category);
}
Then you can observe this event in any controller like below in second controller you can listen categoryDeleted event.
$scope.$on("categoryDeleted", function (event, category) {
// do whatever you want
});
Do not call controller directly from the service, this is a bad practice, not only in AngularJS, but in most languages frameworks.
The problem you have described ("a change in one controller to affect (different) data stored in the other") is a problem of communication between components. You can solve this issue with events, thus there is no need to move data from the second controller to the service.
Let's consider some example:
http://jsfiddle.net/simpulton/XqDxG/
When you click on the LOG button the this.broadcastItem() is invoked, and the 'handleBroadcast' event is broadcasted.
Other constrollers, controllerOne and controllerTwo, handle this event:
$scope.$on('handleBroadcast'
and do the things they want to do.
So, in yor case, you can introduce the 'categoryRemoved' event, and broadcast this event in the first controller. Once the event is broadcasted, your second controller handle it and edit its items.
Also you should pass the removed category in the event (instead of 'msg' in the example), so that second controller has to aware which exactly category has been removed.
In way you want to do that, $rootScope can be used (shared across controllers - modyfing in one, accessing in another), but its generally bad idea. Im not sure if I get it right but its typical situation when you actually need service with controlling some external data.. Its some static json you want to modify? Can you specify it more clearly ? :)

(another) request for clarification about the meaning of "singleton" in Angular

I'm learning angular, experimenting with different ways of using services/factories, and am trying to wrap my head around the unique sense in which they are "singletons".
I have an API service that exposes domain models and wraps functionality for retrieving them from my REST server. This service can be easily comprehended as a singleton in the classic sense: I want a single instance to be shared across my application, with a state that can be observed by many different controllers, enabling those controllers to "synchronize" with each other through the conduit of the service: The controllers stay in sync not by being aware of (and thus coupled with) each other directly, but by being aware of this common service. (side question: is this a correct characterization of the role of a service?)
This is a use-case where a singleton service is clearly and unambiguously appropriate. But:
One of the domain objects that gets returned by the API service is called thread, which is essentially a wrapper around a linked-list of points. In addition to the list of points, a thread has a currentPoint variable and a next() function, which pops the next value from the list and makes it the currentPoint.
My UI visualizes a thread simultaneously in two different ways - in two separate elements with their own controllers and directives. Each of these elements contains a button that, when clicked, calls nextPoint() and thereby changes the state of the thread. When this button is pushed in one element, the state of the thread needs to be updated in both elements - so, here again we have a situation where a service seems ideal.
But, at any given time, there can be an arbitrary number of threads being displayed, each of which should be independent and unaware of each other - which conflicts with (what I understand to be) the "classic" sense of "singleton".
Is there a word for this sort of thing in angular?
I've experimented/looked into this enough to know that it's certainly possible to create these "non-singleton singletons" using factorys, but surely there must be a better term for them than "non-singleton singletons" - I cringed both times I just typed it.
Second, what is the best way of implementing one? Can the strategy illustrated below (which I found in an angular github issue here) be regarded as a best practice?
myApp.factory('myServiceProvider',function(){
var serviceProvider=function(){};
serviceProvider.prototype.foo=function(){};
var service = {
getInstance:function(){ return new serviceProvider(); }
}
return service;
});
//Singleton Services
myApp.factory('myService',['myServiceProvider',function(myServiceProvider){
return myServiceProvider.getInstance();
}]);
//Where non-singletons are required
function myController(myServiceProvider){
var instance_a=myServiceProvider.getInstance();
var instance_b=myServiceProvider.getInstance();
};
//Where singleton service is required
function myOtherController(myService){
myService.foo();
};
An angular singleton is not exactly the classic. A singleton in angular is basically one instance of an object that holds a single state. That state can be data bindable via a services allowing for value sharing. This means that you can have a service property that is bound across all of its uses an app; one change will be reflected everywhere. The singleton persists through the life of the app. If the app is refreshed the singleton will loose value until it is set again by the app via a user interaction or a storage retrieval.
I like the pattern you are using. I also tend to use it. Here is an example of a web storage service I recently made similar to your service, https://github.com/breck421/WebStorage/blob/master/src/js/WebStorage.js.
I hope this helps and feel free to continue this dialog :)
Thanks,
Jordan

SPA design with AngularJS - sharing state across some, but not all, pages

How would you implement something like this in Angular:
I have a multi-page user interaction that shares state across pages/controllers. Page A launches a multi-page process across pages B, C, and D. I need to share state across pages B-C-D but as soon as the user goes back to page A (either at completion, or abandoning halfway through) the shared B-C-D state should go away.
I could put the shared state in a service and that would take care of sharing across pages. But then it's a global singleton for the whole application. Is there a way to ensure the service is disposed if the transaction is abandoned or completed?
In the server-side, Java EE world this was called "conversation scope" - I'm wondering what the equivalent might be in Knockout or Angular.
Or there a better way to approach the design? Should I use nested controllers?
This is a pretty broad question and is going to certainly elicit some opinion based responses. That said, one of the things you can rely on is that services (and factories) are singletons. What that means is if you need to share data between controllers, or across the life of a SPA you can create a service to hold and share that data. That service and its data will exist as long as the page isn't re-loaded.
The basic pattern for a shared data factory is like this is:
// define the shared data service
app.factory("SharedData", function () {
return {
// just one data object for the purposes of the example
sharedDataObject: {}
};
});
Once you have defined the service you can define a controller that uses the service something like:
app.controller("FirstController", function ($scope, SharedData) {
$scope.localData = SharedData.sharedDataObject;
});
Because we have defined the shared data as an object and not as a value - binding to "localData" will allow us to set values that can then be retrieved for as long as the page isn't changed. I put together an example that shows sharing data between two controllers here. This pattern works just as well if the controllers were on separate views.
Again - I'm not sure if this is the recommended pattern but it is one I have seen around and it works pretty well. Best of luck!
NOTE - This answer is referenced in your question - so it probably isn't exactly what you are looking for. That said, I am posting for others that may need a simple method of saving state on an SPA.
If you put the shared state into a service, just add a reset() function to it that gets called when they go to the "A" step or when they complete the process.
And I think you could do it with a nested controller too. You'd probably still need to add a reset() function for handling all the cases.

Best practice for node - mongo - angular

I have an app I am designing using node/mongo/angular, what I am not getting is how is the best way to get my data from mongo into my pages? I can use node, and thru my routes send back data from mongo with my template(hogan in this case), and bind using mustachejs. That works fine for most things. I have one screen that has a decent amount of drop down lists, to bind them for an edit scenario now seems a challenge. I would like to get them bound to an angular model and go about it that way. Is it better to get the data thru the route in node, then use something like ng-init and get it into angular? Or would I be better off not getting the data thru the route in node, and then using angular to perform a "get" request and bind that way?
From the documentation of ng-init, more precisely from the red warning alert at the top of the page...:
The only appropriate use of ngInit is for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
So no, do not use ng-init. While that can be a good strategy for lazy migrations from regular applications to single page applications, it's a bad idea from an architectural point of view.
Most importantly, you lose two things:
An API. The benefit of SPAs is that you have an API and that you're constantly developing and maintaining it, even before it has external users
A clean separation of concerns. Views are strictly limited to presentation, can be cached by the client and all data is transferred through JSON API endpoints.
I would say that the best way to get data from Mongo into your page, is as mnemosyn said, using an API.
Basicly, you can have your API route, f.ex '/api/data' configured and then it can be used by a angular service, (which can use ngResource to make things easier). Any controller that wishes to access this data can use the angular service to get it, do some stuff with it, and then update it using the same angular service.

Categories