select2: load remote data from several sources simultaneously - ruby-on-rails

I need some kind of omnisearch: when user types some name or serial number select2 sends several simultaneous ajax calls to retrieve employees, candidates and devices.
As soon as any of these calls returns data (for example employees) it is shown to user.
So if employee data is returned first we show it. As soon as candidates data is returned we combine it with employees data, sort data by name and show it to user again.
Is it possible?

You need to code by yourself such a thing, by default select2 only loads data attached to the select box, it's your responsability to write javascript that will behave in the following way and it's a non-trivial code.
In general your idea will be load (with multiple async calls) the locations you want and store the data you fetched, after performing operations you need (merging with another json) in the select box and refresh it.

I would think you would want to write this on the backend. Have an endpoint that collalesses all the data you want. Select 2 makes one ajax call to the endpoint to retrieve all the data you need in one go.

Related

Saving data accross API's in Gramex

I am calling the same database query in multiple form handlers, I want to access the data once for processing and store it to use them across multiple form handlers.
Formhandler, caches the data after your first query so essentially you are not querying to the DB if your query remains same.
And if you are firing the same query through multiple formhandlers you could essentially write a transform function which can do all the different processing after fetching the data (Formhandler will take care of caching and you will not query from different patterns).
/dataapi?mode=getsalesdata&otherparams=.......
/dataapi?mode=getavgsales&otherparams=........
You could also use query function in formhandler to control the dynamic behaviour of your query.
Provide some more details around the use-case to have a tailored response.

Sorting OData model in SAPUI5

Dear SAPUI5 Developers,
I developed a SAPUI5 Fiori Worklist project by using WebIDE template projects.
In the Component.js file the OData model has been fetched.
var sServiceUrl = this.getMetadata().getManifestEntry("sap.app").dataSources.mainService.uri;
var oModel = new sap.ui.model.odata.ODataModel(sServiceUrl, {
json: true,
loadMetadataAsync: true
});
oModel.attachMetadataFailed(function() {
// Call some functions from APP controller to show suitable message
}, this);
this.setModel(oModel, "BrandSet");
This part of code causes a call to OData server to fetch data from the remote server.
Now I want to order the data in backend and then receive the data. Assume the sorting function has been implemented correctly in the backend.
Thus, if I use $orderby=name or $orderby=price it has to be sorted by name or price respectively.
In some toturial they said for ordering use sorter option inside of the XML view file. Like here:
https://sapui5.hana.ondemand.com/#docs/guide/c4b2a32bb72f483faa173e890e48d812.html
Now my questions are:
How to apply this sorting inside of the Component.js file where the Model is initiated?
The second question is how to apply this ordering when we apply a filter to the model? Like the example that in the following link applied filter:
https://sapui5.hana.ondemand.com/#docs/guide/5295470d7eee46c1898ee46c1b9ad763.html
In fact I am looking for a function or any kind of method that add the $orderby=xxx to the OData service call.
I found a way here: https://sapui5.hana.ondemand.com/docs/api/symbols/sap.ui.model.odata.ODataModel.html#constructor
If I use mParameters.serviceUrlParams then I can add some URL parameter to the service request but it has been said "these parameters will be attached to all requests". Does it mean if I add the $orderbywith this method then I can not get rid of that in the further requests on that data model for example for filtering?
An app would normally be structured a bit differently to what you propose. The general assumption is that there is a lot of data available from the backend and to load all this data at once can cause performance problems, particularly when used over a mobile phone network. Furthermore, the data is an oData Entity Set, that is, a list of many items of the same type, so the data would be presented in the UI with a list or table.
Typically the app would then show the data in some kind of list, such as sap.m.List or sap.m.Table. These controls are designed to work with large volumes of data and would load initially the first 20 items from the entity set. Only when the user scrolls down the list of data would additional items be loaded. Also, with these controls the user can decide to sort or filter the data according to certain fields in your data.
Assuming that your app is work like this, here is the standard approach.
The Main model (as defined in the manifest) would not be loaded in Component.js, but loaded via the binding defined in the xml views of the app. In the views you could define a fixed sort and/or filter in the binding or you could allow the user to set the sort and filter criteria. This would be handled programmatically in the respective controllers. Normally the changes that the user makes to the sort and filter would be applied separately. For example, he/she chooses an new sort order, the oData is reread and the new sort order shown in the UI. Then the user may chose a filter criteria, and this is applied too. Of course, in your programming logic in the controllers you would need to have applied any default sort and filter criteria and then maybe combine or replace these with the criteria selected by the user.
To see an example of this, I would suggest to look at the Template Application “SAP Fiori Master-Detail Application” in the WebIDE.

Breeze projection query from already-loaded entity

If I use breeze to load a partial entity:
var query = EntityQuery.from('material')
.select('Id, MaterialName, MaterialType, MaterialSubType')
.orderBy(orderBy.material);
return manager.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
function querySucceeded(data) {
var list = partialMapper.mapDtosToEntities(
manager, data.results, entityNames.material, 'id');
if (materialsObservable) {
materialsObservable(list);
}
log('Retrieved Materials from remote data source',
data, true);
}
...and I also want to have another slightly different partial query from the same entity (maybe a few other fields for example) then I'm assuming that I need to do another separate query as those fields weren't retrieved in the first query?
OK, so what if I want to use the same fields retrieved in the first query (Id, Materialname, MaterialType, MaterialSubType) but I want to call those fields different names in the second query (Materialname becomes just "name", MaterialType becomes "masterType" and so on) then is it possible to clone the partial entity I already have in memory (assuming it is in memory?) and rename the fields or do I still need to do a completely separate query?
I think I would "union" the two cases into one projection if I could afford to do so. That would simplify things dramatically. But it's really important to understand the following point:
You do not need to turn query projection results into entities!
Backgound: the CCJS example
You probably learned about the projection-into-entities technique from the CCJS example in John Papa's superb PluralSight course "Single Page Apps JumpStart". CCJS uses this technique for a very specific reason: to simplify list update without making a trip to the server.
Consider the CCJS "Sessions List" which is populated by a projection query. John didn't have to turn the query results into entities. He could have bound directly to the projected results. Remember that Knockout happily binds to raw data values. The user never edits the sessions on that list directly. If displayed session values can't change, turning them into observable properties is a waste of CPU.
When you tap on a Session, you go to a Session view/edit screen with access to almost every property of the complete session entity. CCJS needs the full entity there so it looks for the full (not partial) session in cache and, if not found, loads the entity from the server. Even to this point there is no particular value in having previously converted the original projection results into (partial) session entities.
Now edit the Session - change the title - and save it. Return to the "Sessions List"
Question
How do you make sure that the updated title appears in the Sessions List?
If we bound the Sessions List HTML to the projection data objects, those objects are not entities. They're just objects. The entity you edited in the session view is not an object in the collection displayed in the Sessions List. Yes, there is a corresponding object in the list - one that has the same session id. But it is not the same object.
Choices
#1: Refresh the list from the server by reissuing the projection query. Bind directly to the projection data. Note that the data consist of raw JavaScript objects, not entities; they are not in the Breeze cache.
#2: Publish an event after saving the real session entity; the subscribing "Sessions List" ViewModel hears the event, extracts the changes, and updates its copy of the session in the list.
#3: Use the projection-into-entity technique so that you can use a session entity everywhere.
Pros and Cons
#1 is easy to implement. But it requires a server trip every time you enter the Sessions List view.
One of the CCJS design goals was that, once loaded, it should be able to operate entirely offline with zero access to the server. It should work crisply when connectivity is intermittent and poor.
CCJS is your always-ready guide to the conference. It tells you instantly what sessions are available, when and where so you can find the session you want, as you're walking the halls, and get there. If you've been to a tech conference or hotel you know that the wifi is generally awful and the app is almost useless if it only works when it has direct access to the server.
#1 is not well suited to the intended operating environment for CCJS.
The CCJS Jumpstart is part way down that "server independent" path; you'll see something much closer to a full offline implementation soon.
You'll also lose the ability to navigate to related entities. The Sessions List displays each session's track, timeslot and room. That's repetitive information found in the "lookup" reference entities. You'll either have to expand the projection to include this information in a "flattened" view of the session (fatter payload) or get clever on the client-side and patch in the track, timeslot and room data by hand (complexity).
#2 helps with offline/intermittent connectivity scenarios. Of course you'll have to set up the messaging system, establish a protocol about saved entities and teach the Sessions List to find and update the affected session projection object. That's not super difficult - the Breeze EntityManager publishes an event that may be sufficient - but it would take even more code.
#3 is good for "server independence", has a small projection payload, is super-easy, and is a cool demonstration of breeze. You have to manage the isPartial flag so you always know whether the session in cache is complete. That's not hard.
It could get more complicated if you needed multiple flavors of "partial entity" ... which seems to be where you are going. That was not an issue in CCJS.
John chose #3 for CCJS because it fit the application objectives.
That doesn't make it the right choice for every application. It may not be the right choice for you.
For example, if you always have a fast, low latency connection, then #1 may be your best choice. I really don't know.
I like the cast-to-entity approach myself because it is easy and works so well most of the time. I do think carefully about that choice before I make it.
Summary
You do not have to turn projection query results into entities
You can bind to projected data directly, without Knockout observable properties, if they are read-only
Make sure you have a good reason to convert projected data into (partial) entities.
CCJS has a good reason to convert projected query data into entities. Do you?

ASP.NET MVC "Loading..." gif during initial API call

I'm creating an ASP.NET MVC 4 web application that displays different data depending on the id number in the query string. It's designed to give users safety information specific to them based on what county they live in, what type of job they have, etc. They don't use a user name to log in, they just click on a link in their email like: http://www.mysite.com?id=123456
In Session_Start of global.asax, I pull down their id from the query string and search for a record that matches through an API call. This returns a bunch of fields in a DataSet which I turn into a DataTable. I then use a foreach loop to loop through the DataTable and use Session.Add(name, value) to create the session variables which I will plug into the view.
It can take up to 10 seconds for the API call to go through, so I want to put up some sort of "Loading..." gif animation until the API call is complete. Once the initial API call is complete I don't have to do any more API calls.
What's the best way to accomplish this?
If you need a loading animation, then you need a rendered HTML page. That means making your API call via AJAX. You can still encapsulate the call in your own view, just call your view with AJAX. Once you're initiating the call with JavaScript, it's trivial to add a loading animation. If you don't use AJAX, there's nothing you can do about it, as the server won't return the response until the view has finished processing.

ASP.NET MVC: where to keep entity being edited by user

Here's a simple problem: users want to edit products in grid-like manner: select and click add, select and click add... and they see updated products list... then click "Finish" and order should be saved.
However, each "Add" have to go to server, because it involves server-side validation. Moreover, the validation is inside domain entity (say, Order) - that is, for validation to happen I need to call order.Add(product) and then order decides if it can add the product.
The problem is, if I add products to order, it persists changes so even if users do not click "Finish" the changes will still be there!
OK, I probably shouldn't modify the order until users click Finish. However, how do I validate the product then? This should be done by the order entity - if product is already added, if product does not conflict with other products, etc.
Another problem, is that I have to add product to order and "rebuild view/HTML" based on its new state (as it can greatly change). But if I don't persist order changes, the next Add will start from the same order each time, not from the updated one. That is, I need to track changes to the order somehow.
I see several solutions:
Each time the user click Add, retrieve order from database, and add all new products (from the page), but do not persist it, just return View(order). The problem is I cannot redirect from POST /Edit to GET /Edit - because all the data only exists in the POST data, and GET lose it. This means that Refresh page doesn't work in a nice way (F5 and you get duplicated request, not to mention the browser's dialog box)).
Hm, I thought I can do redirect to GET using TempData (and MvcContrib helper). So after POST to /Edit I process business logic, gets new data for view, and do RedirectToAction<>(data) from MvcContrib that passes data via TempData. But since TempDate is... temp... after F5 all the data is lost. Doesn't work. The damn data should be stored somewhere, this way or another.
Store "edit object" in Session with the POST data (order, new products info). This can also be database. Kind of "current item - per page type". So page will get order ID and currently added products from this storage. But editing from multiple pages is problematic. And I don't like storing temp/current objects in Session.
Marking products as "confirmed" - if we do /order/show, we first cleanup all non-confirmed products from the order. Ugly and messy logic.
Make a copy of the order - a temporary one - and make /Edit work with it. Confirm will move changes from temp order to persisted. A lot of ugly work.
Maybe some AJAX magic? I.e. "Add" button won't reload page but will just send new + already added products to server, server will validate as order.Add(products + newproduct) but will not persist changes, will just return updated order information to re-build the grid. But Refresh/F5 will kill all user-entered info.
What else?
Is this problem common? How do you solve similar ones? What's the best practices?
It depends a lot on how you implement your objects/validation, but your option number 5 is probably the best idea. If AJAX isn't your thing, you can accomplish the same thing by writing the relevant data of already-added-but-not-saved entries to hidden fields.
In other words, the flow ends up something like this:
User enters an item.
Item is sent to the server and validated. The view is returned with the data entered by the user in hidden fields.
User enters a second item.
Item is sent to the server, and both items are validated. The view is returned with the data for both items in hidden fields.
etc.
So far as F5/Refresh killing entered data... In my experience this isn't too much of a problem. A more pressing concern is the back/forward buttons, which need to be managed with something like Really Simple History.
If you DO want to make the page continue to work after a refresh, you need to do one of the following:
Persist the records to the database, associated with the current user in some way.
Persist the records to session.
Persist the records to the query string.
These are the only storage locations available that persist through both redirection and refreshes.
If I were you, I would come up with something which resembles option 5. And since you say that you are comfortable with Ajax you can try this. But before you do this, you should move your validation logic outside the Order.Add() method. Maybe you can move it to another public function called Validate() which returns a bool. And you can still call the same Validate() in the Add() method, thereby doing the necessary validation before you add the order.
Try to do the validation on the client side. If you are using jQuery, you can use the jquery validate plugin. But, if this is not possible for some reason (such as when you need to validate stuff against a database). You should do your validation on the server side and just return a JSON object with the 'success' boolean flag and an optional message, just a way to mark that the data is valid. You would allow the user to add a new product only if the previous Order was valid.
And when the user hits finish send the product to the server and do the validation again, but persist the order in this round-trip.
Now, If I had a complete say in this, I wouldn't even go to the extent of doing validation whenever a product is added/edited. I would just do the validation whenever the customer hits finish. That would be the simplest solution. But, maybe I am missing something.

Resources