I have an architectural question about data retrieval for multiple widgets.
I am building a large javascript application (a mini-SPA) with AngularJS. I want to create a very modular Dashboard application with interactive widgets that the user can choose to include, exclude or reposition in the containers of the layout system. The user can interact with each widget, causing an individual refresh of it’s data and more. Each widget will be displaying very different data from other widgets.
So far architecturally, each widget will be represented by these AngularJS components:
a partial view template (to show the user the data)
a controller (to implement widget behavior and handle the success callback of the corresponding service)
a service (to retrieve data with $http and return a promise object to the calling controller)
Thus each widget has the ability to pull it’s own data through an Angular Service calling a particular endpoint.
Now, when the user arrives on the Dashboard Page containing possibly 5 widgets, I don’t want to make 5 individual parallel AJAX calls to 5 different server endpoints. That wouldn't be efficient; I'd like to reduce parallel requests to the server.
Instead, on arrival to the page, I’d rather make a single AJAX call by calling an endpoint that has aggregated all the data of the 5 widgets.
QUESTION: Supposing that the server can bundle/merge all the data from the 5 widgets in 1 JSON payload in a clever wrapper, then in the AngularJS application, how would I retrieve and distribute that data to the 5 widget controllers, so that they can initialize themselves with the fresh server data?
Of course, I’d want to retain the ability for any single widget to refresh only themselves. Though behavior beyond arriving on the Dashboard page isn’t what I’m asking about in this question.
Maybe there are articles out there that talk about this, but I haven’t found one yet.
I have already thought of one architectural idea that I think is ‘good’, but I wonder if there are better solutions.
Possibility) In addition to the 5 Angular Services to make AJAX calls, introduce a 6th called WidgetAggregateService. When it’s retrieveAllAndBroadcast() method is executed, this service would handle the success callback itself and then publish the payload to the 5 controllers using $rootScope.$emit(). Thus the WidgetAggregateService would be using the Mediator Pattern (or PubSub Pattern) on $rootScope that the 5 controllers can subscribe to with $rootScope.$on(). Each widget's controller can grab the relevant information in the aggregate data payload.
My team and I came up with a solution…
API Contract
We have a developed a API contract that allows us to make requests to the server for 1 or more widgets (including passing relevant request arguments) that will return 1 or more widget responses in a JSON wrapper. Thus we can do retrievals in these ways:
Single Widget Retrieval
Multiple (Aggregate) Widget Retrieval - We are requesting data for 2 or more widgets at a time.
in a single call to the server.
Deliver Data to Widget Controllers from an Aggregated Retrieval
1) Aggregated Retrieval: We have an AngualrJS “page” controller that is responsible for making the aggregated retrieval for all the widgets on the page upon page load. It makes the request for all 5 widgets on the page by delegating the AJAX request to an Ng factory to handle data retrieval—we’ll call that “PageResourceFactory”.
2) Forward to Individual Widget ResourceFactories: Upon successfully getting data back the “PageResourceFactory”, it calls another factory helper to forward the relevant responses to the individual widget resource factories calling their set methods. Thus at this point, all 5 widget resource factories have their data set.
3) Widget Controllers Subscribe to New Data: During page initialization each widget controller has already setup a subscription to their own resource factories to essentially listen for when new data has been set (via their resource factory set methods). THUS, the controllers can know when the data has changed (whether or not they the widget controller initiated a retrieval or not).
4) Widget Controllers Bind Data: Each widget controller is ‘notified’ of a data change, and thus can respond accordingly by putting it on the scope to bind to the view.
Single Retrieval
This works just a standard AJAX retrieval.
1) Controller makes request via a resource factory.
2) The resource factory with the aid of $http performs the AJAX request and passes the promise object back up the the controller.
3) The controller takes the data (after a successful promise call) and binds it for the view to display.
This is the way we approached the problem. I'm sure there are other possibilities.
Related
I have various page in my project and each page contain lots of drop down.
For getting options of drop-down from web-api and then i store this variable in angular service variable for further use in another view.
But i didn't get the way where should i call web-api to get drop-down data so that it doesn't matter which page should i open first or by default???
And i get options of drop-down every where.Currently i calling web-api in the controller which is correspond to my first view of application.
My approaches regarding this:
Method 1: I create a root controller in which i call angular service which call web-api to get data. The view is already render on view-port before get the the from web-api.
Method 2: i call angular service which call web-api in controller(not root controller which to specific to a view) and populate data in drop-down after successful callback from service so this working fine but it's not generic
Services/Factory are singleton, so I believe you should call the web api in your service rather than in controller and then passing the data to service.
EDIT -
If you are concern about the display of view before the data then you can use resolve as resolve can wait for data to become available before showing a view.
I have a variable in my JavaScript which contains the id of the clicked row in the master grid. I want to pass it to the groovy service page that handles my child grid so that it can filter the rows based on that id. How do I do that?
The problem is that your javascript-based grid runs on the client, while the page is rendered server-side. Therefore, some communication must take place in order to instruct your application to filter rows based on what the user selects.
Grails uses the MVC architecture, this means that there is a controller that takes care of answering the requests generated from the client. To answer these requests, the Controller can make use of the Views (.gsp files). So when you call to the URL controller/index you may make use of an index.gsp view to render your page.
What you need to do is to make an ajax call to a controller method (e.g. controller/getFilteredRows) that gets as input the selected row (could be its id) and based on some logic fetches all the required information and sends them back to the client encoded for example using JSON.
Now the client knows the rows it has to display, hence you can update your grid.
I have a theory as to how to approach them, and was looking for some guidance on how to solve this problem and see if I am on the right path, because I am not sure.
I have a web app for a project I am building, and I have a database that I need to query for specific information. I have a search button that is attached to a function in my MainController, and I need to have my data passed on to my result.html file, which displays information from a ResultsController.
This is my theory for how to get this working using fake data, and an html request (which uses promises I imagine?)
for fake/test data, I stored an array with objects that represents JSON data in my services file that was basically the parent to ResultsController and MainController, and ResultsController would take in that information and display it on the screen.
For querying a database, my search function would search the database, and fill/replace the array in my services file with additional information. By virtue of changing that array of objects in my services, my results.html should pull down new data automatically when I click search, since the ResultsController has access to that same JSON data. (also, clicking search submits the query and then does $location.path("/results") after to get to the results page).
For querying a database and dynamically changing the information on a page, are these the right steps to submitting a request to a database in pulling information down upon each "search" request?
You are on the right track in using a service to share logic and data between the two controllers. This is generally seen as best practice - and it is better than the approach that is sometimes used of putting the logic and data in a parent controller, and using scope to access it in child controller.
The style guide linked to above is worth a read if you are looking for some guidance on best practice in setting up an angular app (https://github.com/johnpapa/angular-styleguide).
Suppose I have a single page application that makes AJAX requests to http://www.somesite.com/resources?lang=en.
Now, let's say that my application has a special variable for the request's languages, that is, if the variable's value is en, then the AJAX request will send a query param lang=en.
For now, the two possible values are en and es.
This variable's value can be changed dynamically by the user (clicking a button).
So, if we are using the application with language = en, then the application will send the lang=en query parameter. If the user changes the language to es, then I want the application to resend all the AJAX requests but now with lang=es query parameter.
It would be like refreshing the website, but asynchronously via AJAX requests.
I have been thinking this yesterday and I can't find a way to handle this logic in an AngularJS application.
I'm not an expert in AngularJS, but I understand the concepts of modules, directives, services and controllers.
What would be the best approach to handle this scenario? That is, I would like to avoid having to call each AJAX request manually, I'd rather create an automatic way of doing this.
Have you tried any AngularJS plugins?
First that comes to mind is Angular translate
Best way to concate the ajax url with lang parameter and request again.
So you will get all new data base on lang parameter, won't forget to handle cache before requesting the ajax call.
I just started writing an application with AngularJS and I have a couple questions about data persistence across routes. Here a plunker of a simple list application that demonstrates my question. Right now, each time a controller is loaded an HTTP request is being made. I only want a single HTTP request to be sent when the app is loaded and then be able to use that data in both of my views.
Question 1: When I click on a list item, how can I use the data that was loaded in ListCtrl rather than issuing another request to pull that same data(but for a single item)?
Question 2: If I've click on an item and then click the back button, how can I make it so that ListCtrl doesn't re-issue a request to get all the list items?
You are probably looking for the $cacheFactory. You can use it to construct cache objects to store your data.
Also, this guy has a pretty good post on using it for what you are looking for, so I won't reinvent the wheel here.
http://www.phase2technology.com/blog/caching-json-arrays-using-cachefactory-in-angularjs-1-2-x/
Answer 1 : You can save the data on $rootScope so the data accessible by all $scope.
Answer 2 : You can cache your ajax so AngularJS will only request the data at first service call, and use it for the rest service call.