I am making multiple Ajax calls to retrieve insurance quotes from different providers with the intention of aggregating and sorting the results. My simplified code looks like this:
for (var i = 0; i < providerList.length; i++) {
$.ajax({
url : "quote-request/"+ providerList[i] +".php",
type: "GET",
data : formData,
dataType:"json",
success: function(results) {
$.each(results, function(index, value) {
$("#results").append("<div>" + value["provider-name"] + value["policy-name"] + value["grand-total"] + "</div>");
})
}
});
}
I am making multiple Ajax calls to retrieve insurance quotes from different providers with the intention of aggregating and sorting the results. My simplified code looks like this:
for (var i = 0; i < providerList.length; i++) {
$.ajax({
url : "quote-request/"+ providerList[i] +".php",
type: "GET",
data : formData,
dataType:"json",
success: function(results) {
$.each(results, function(index, value) {
$("#results").append("<div>" + value["provider-name"] + value["policy-name"] + value["grand-total"] + "</div>");
})
}
});
}
Which produces:
<div id="results">
<div>ProviderA Policy1 12.34</div>
<div>ProviderA Policy2 9.50</div>
<div>ProviderB Policy1 22.76</div>
</div>
However I would like the results to be ordered in ascending order of grand-total as each Ajax call finishes so each new result is automatically inserted in the correct place:
<div id="results">
<div>ProviderA Policy2 9.50</div>
<div>ProviderA Policy1 12.34</div>
<div>ProviderB Policy1 22.76</div>
</div>
The only way I can think of doing this is to save each result to an array after every Ajax call, then sort the array and output the results but it seems slightly redundant to keep building and outputting the same array every time a new quote is retrieved. Is there a better way of doing this?
To clarify, the final script will make around 10 Ajax calls and load around 40 results so we are not talking huge datasets here. Also it is possible that one or more quotes will have the same grand-total, in which case it is not important which es first. Each quote will also have a unique identifier, policy-id if this is useful here.
Share Improve this question edited Feb 13, 2017 at 19:37 Dimitrios Desyllas 10.2k17 gold badges83 silver badges195 bronze badges asked Feb 13, 2017 at 19:21 sixoftwelvesixoftwelve 1432 silver badges9 bronze badges 1- I don't see any other ways than re-building each time. You could parse the table for each new entry and try to figure out where it goes but that would take a lot more process than simply rebuilding the app. You could also just make one calls that takes every data, sort it and build your table only one time. – Nicolas Commented Feb 13, 2017 at 19:23
3 Answers
Reset to default 3Yes, it is much faster if you can insert a DOM element directly in order. And this can be done. You can essentially use the DOM as a pseudo-array, and use the data
attribute within the DOM to keep track of your values. You can write a short script to search your "pseudo-array' in the DOM and find the appropriate index to insert your new element(s).
Here is a short function that should work for you. I also mocked it up in a fiddle with some random data on a timer to show how it will work:
function insertInline(providerName, policyName, grandTotal) {
var curDomElement;
var prevDomElement;
var insertBefore;
$('#results div').each(function(index) {
prevDomElement = curDomElement;
curDomElement = $(this);
if (parseInt(curDomElement.data('grandtotal')) > grandTotal) {
insertBefore = curDomElement;
return false;
}
});
if (insertBefore) {
$("<div data-grandTotal='" + grandTotal + "'>" + providerName + policyName + grandTotal + "</div>").insertBefore(insertBefore);
} else {
$("#results").append("<div data-grandTotal='" + grandTotal + "'>" + providerName + policyName + grandTotal + "</div>");
}
}
And in your sample, you would use it essentially like this:
for (var i = 0; i < providerList.length; i++) {
$.ajax({
url : "quote-request/"+ providerList[i] +".php",
type: "GET",
data : formData,
dataType:"json",
success: function(results) {
$.each(results, function(index, value) {
insertInline(value["provider-name"], value["policy-name"], parseInt(value["grand-total"]));
})
}
});
}
Working sample: https://jsfiddle/mspinks/vnofjobu/
You can mark each result with a span having html5's data-
attrubute:
http://html5doctor./html5-custom-data-attributes/
So you can create the divs like that:
<div id="results">
<div data-provider="ProviderA" data-policy="Policy1" data-grandtotal="9.50">ProviderA Policy1 12.34</div>
<div data-provider="ProviderA" data-policy="Policy2" data-grandtotal="9.50">ProviderA Policy2 9.50</div>
<div data-provider="ProviderA" data-policy="Policy2" data-grandtotal="22.76" >ProviderB Policy1 22.76</div>
</div>
Afterwards you can retreive the data like that using this function:
var getDataFromDom=function(){
var resultData=[];
$("#results").children().each(function(idx,val){
var result={
'provider':$(val).data('provider'),
'policy':$(val).data('policy'),
'grand-total':parseFloat($(val).data('grandtotal'))
}
resultData.push(result);
});
return resultData;
}
Afterwards you can use the Javascript's sort function to sort it: http://www.w3schools./jsref/jsref_sort.asp
Then the only think you need is to when you click the appropriate sorting button:
* Get the data-
attributed from div.
* Store them into an array.
* Sort them by using javascript's sort()
function with the correct callback.
* Remove all elements from the div.
* Iterate the array and append them inside the div.
And you will be ok.
PS I used the latest version of Jquery (3.1.1) if you use an earlier one replace the data()
function with attr()
one eg. the $(val).data('provider')
will be $(val).attr('data-provider')
.
I thought of something that might work. You can assign the grand-total (the item that you're sorting by) to an attribute in each div. Then you can use jQuery to place items in the results
div based on the grand-total.
So when you get the first item, you'll just add that to the results
div, but you'll also give the div an attribute (I called it value, you can call it whatever you want) like so:
<div value='what-grand-total-is'></div>
Then for all the other items, you'll get the current item's grand total, run down the existing list of results, and for each item, check the grand-total and if you e across a child that has a greater grand-total than the current item's, place the current item before that child.
for (var i = 0; i < providerList.length; i++) {
$.ajax({
url : "quote-request/"+ providerList[i] +".php",
type: "GET",
data : formData,
dataType:"json",
success: function(results) {
$.each(results, function(index, value) {
// no children, so append first time
if( $('#results').children.length == 0 ) {
// assign attribute value (or whatever name you want) to div
$("#results").append("<div value=" + value["grand-total"] +">" + value["provider-name"] + value["policy-name"] + value["grand-total"] + "</div>");
// if there are items in #results
} else {
// assuming this is returned as type integer
var currentTotal = value["grand-total"];
// for every child
$('#results').children('div').each(function () {
// get grand-total from attribute of current div
var childTotal = this.attr('value');
// convert current div's grand total value from string to float, so we can pare values
childTotal = parseFloat(childTotal);
// if the div we're currently at is greater than or equal to the current result total
if (currentTotal <= childTotal) {
// place the current result in front of the div we're at
$(this).before("<div value=" + value["grand-total"] +">" + value["provider-name"] + value["policy-name"] + value["grand-total"] + "</div>"); // place the current result total before the current child
}
});
}
})
}
});
}
This approach should work for any number of AJAX requests and also with this way, you don't have to keep track of an array and it can append the data as it goes.