Sorting multiple API's by price in a table - javascript

This is going to be confusing but probably an easy answer.
I have two api links in a json format. Pulling data into a table.
At the moment, all of the API1 is being put in the table first and below that API2 is then being put in.
Both of the api's have prices in £XX.XX format.
What I am looking for is the table to be sorted by price. So that for example API1 first 2 results are the cheapest, then API2 then API1 and so on and so forth.
I have posted my code below for you to look at.
Table.html
<table class="pull-left table-fill" id="Bananna">
<thead>
<tr>
<th class="table-hover">Vendor</th>
<th class="table-hover">Section</th>
<th class="table-hover">Amount Of Tickets</th>
<th class="table-hover">Price Per Ticket</th>
<th class="table-hover">Link</th>
</tr>
</thead>
</table>
</body>
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="js/1.js"></script>
<script src="js/2.js"></script>
1.js and 2.js are exactly the same.
$.ajax({
type: 'GET',
crossDomain: true,
dataType: 'json',
url: 'API LINK HERE',
success: function (json) {
//var json = $.parseJSON(data);
for(var i =0;i < json.results.length;i++) {
var section = json.results[i].section;
var no = json.results[i].avalible;
var price = json.results[i].price;
var button = "<button class='redirect-button' data-url='viagogo.com'>Compare</button>";
$("#Bananna").append("<tbody><tr><td>"+section+"</td><td>"+no+"</td><td>"+price+"</td><td>"+button+"</td></tr></tbody>");
$("#Bananna").find(".redirect-button").click(function(){
location.href = $(this).attr("data-url");
});
}
},
error: function(error){
console.log(error);
}
});

Don't touch the table until you've got both result sets, that's just going to make sorting more difficult. Define some global results array and populate it with the AJAX data using concat.
var results = [];
//on success of each AJAX call
results = results.concat(json.results);
To ensure both sets of data have been loaded before sorting just include the second AJAX call in the complete function of the first or use recursion if you may have additional AJAX requests in the future.
After you have all the data you can sort by price:
results.sort(function(a,b){
return a.price-b.price;
});
Finally, step through the sorted array and append as you did before.
EDIT:
Instead of making a bunch of files which are all identical, define a recursive function to load an array of API urls like this:
function loadURLs(urls,callback){
//are there more urls to AJAX?
if(urls.length==0){
//no: call the callback function
callback();
}else{
//yes: make the AJAX call...
$.ajax({
type: 'GET',
crossDomain: true,
dataType: 'json',
url: urls[0],
success: function (json) {
//put data into the results array
results = results.concat(json.results);
//load the remaining urls
loadURLs(urls.slice(1),callback);
}
}
}
}
This function accepts an array of URL links. It will go through one by one and load the json data into the global results array. After it has gone through all the links it will call the callback function. Inside the callback function you can sort your array once and then append to your table. Your final js would look something like this:
//define loadURLs function here
//global results array
var results = [];
//define all your links links here
var myURLs = ['API LINK 1','API LINK 2'];
loadURLs(myURLs,function(){
//all json data has been loaded, sort
results.sort(function(a,b){
return a.price-b.price;
});
//iterate over the sorted array and append
for(var i=0;i<results.length;i++){
//append to table
}
});

Related

Using ajax in a callback where the parent process itself relies on an ajax call

I'm working with an application that uses DataTables to generate a HTML table which is populated by data from an ajax request.
This is fairly simple:
var substancesTable = $('#substancesTable').DataTable({
"processing": true,
"serverSide": true,
"searching": false,
"ajax": {
"url": "/get-substances.json",
"method": "POST",
"cache": false,
"dataSrc": function (json) {
// Update non-Datatables UI elements and perform other functions based on the ajax response
$('#numSubstances').html(json.recordsTotal);
drawOptionsButton(json.isFiltering);
// Must return data for DataTables to work
return json.data;
}
},
// ...
});
There is a callback which DataTables provides, called rowCallback (https://datatables.net/reference/option/rowCallback) which allows post processing of table rows after the table has been drawn. The key thing here is that it's after the ajax request to /get-substances.json; the table must be populated with data because this callback is used to manipulate data within it at that point.
Within rowCallback I'm providing an array of row ID's in my table - that is to say ID's which correspond to <tr> elements inside #substancesTable - and I go on to expand these rows. I can do this manually by hardcoding in an array of row ID's, e.g.
var substancesTable = $('#substancesTable').DataTable({
// ...
"rowCallback": function(row) {
var id = $(row).find('td:first').text();
var index = $.inArray(id, ['4', '7']); // hardcoded array
if (index !== -1) {
var tr = $(row).closest('tr');
var row = substancesTable.row( tr );
row.child.show();
tr.addClass('active');
}
});
The array I've hardcoded means rows 4 and 7 are expanded after the table has been populated, which is equivalent to the user clicking on them.
The problem I have is that I don't want to hardcode the array. The application stores the equivalent of var index in Redis (cache) meaning that we can grab the data easily even if the user leaves the page. So I have added a second ajax request (outside the var substancesTable... block) to obtain the Redis data. This makes an ajax request to populate an array, activeRows:
var activeRows = [];
$.ajax({
url: '/view-substance/get-active-rows',
method: 'post',
cache: false,
}).done(function(data) {
activeRows = data;
console.log(activeRows);
});
I understand that the nature of ajax means my code is asynchronous. In some cases the ajax request shown above will complete before the DataTable is drawn, so I get the console.log(activeRows) appearing before the table is rendered, and in other cases it happens afterwards.
What is the correct way to make this second ajax request such that the values from it can be used in place of the hardcoded array? I appreciate I will need to convert the response to an array (since it's still JSON in the console.log statement). But my question is focused on where to put this code such that it can be used reliably inside rowCallback?
I have read How do I return the response from an asynchronous call? and understand about the async nature. I can't work out how to structure this to be used in a callback that's already part of an ajax request.
The application uses DataTables version 1.10.16 and jquery 3.2.1
You can actually use the ajax option to:
Make the first AJAX request which retrieves the active rows.
Once the active rows are retrieved, make the second AJAX request which retrieves the table data.
Example: (see full code and demo here)
var activeRows = [];
function getActiveRows() {
return $.ajax({
url: '/view-substance/get-active-rows',
type: 'POST',
dataType: 'json'
...
}).done(function(data){
activeRows = data;
console.log(activeRows);
});
}
function getTableData(data, callback) {
return $.ajax({
url: '/get-substances.json',
type: 'POST',
dataType: 'json',
'data': data // must send the `data`, but can be extended using $.extend()
...
}).done(callback); // and call callback() once we've retrieved the table data
}
$('#example').dataTable({
ajax: function(data, callback){
getActiveRows().always(function(){
getTableData(data, callback);
});
},
rowCallback: function(row, data){
...
}
});
UPDATE
In the above example, I separated the AJAX calls into two different functions mainly to avoid long indentation in the ajax option when you call the $('#example').dataTable(). The code would otherwise look like:
var activeRows = [];
$('#example').dataTable({
ajax: function(data, callback){
// 1. Retrieve the active rows.
$.ajax({
url: '/view-substance/get-active-rows',
type: 'POST',
dataType: 'json'
...
}).done(function(res){
activeRows = res;
console.log(activeRows);
}).always(function(){
// 2. Retrieve the table data.
$.ajax({
url: '/get-substances.json',
type: 'POST',
dataType: 'json',
'data': data // must send the `data`, but can be extended using $.extend()
...
}).done(callback); // and call callback() once we've retrieved the table data
});
},
rowCallback: function(row, data){
...
}
});
I used the .always() so that the table data would still be retrieved in case of failures in retrieving the active rows.
You could solve your problem with Promises. Promises are objects that help you manage and coordinate asynchronous tasks. Your case would look something like this:
var activeRows = [];
var substancesTable = $('#substancesTable').DataTable({
// ...
});
var pDataTable = new Promise(function(resolve, reject){
// you wan't to resolve just once,
// after the table has finished processing the received data.
// (You may want to change draw to an event that's more suitable)
substancesTable.one('draw', resolve);
});
var pOpenRows = new Promise(function( resolve, reject ){
$.ajax({
url: '/view-substance/get-active-rows',
method: 'post',
cache: false,
}).done(function(data) {
// you can either save your rows globaly or give them to the resolve function
// you don't have to do both
activeRows = data;
resolve( data );
});
});
// Here we basically create a third promise, which resolves (or rejects)
// automatically based on the promises in the array.
Promise.all([pDataTable, pOpenRows])
.then(function( values ){
// expand your table rows here
// Note: if you gave your rows to the resolve function you can access
// them here in values[1] (pDataTable's data would be in values[0])
});
In case you want to learn more about Promises:
https://developers.google.com/web/fundamentals/primers/promises
https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://scotch.io/tutorials/javascript-promises-for-dummies
For details on browser support you may look here:
https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://caniuse.com/#search=Promise

how to count no of times a variable is in a array in javascript in codeigniter?

hi guys i am trying to create a like system where when users like a post it gets saved in the database that this user has liked this post now i need to count the no of times 'like' has been done.now i used a column type to save the like whenever someone click but when i am retrieving how many likes are on a post how can i count how many likes has been done on this post.here is my code
script
function select_likes(post_id)
{
var Post_id=post_id;
var User_id = $('.id_data').attr('value');
jQuery.ajax({
type:'POST',
url:'<?php echo base_url("user/select_likes"); ?>',
data: {Post_id:Post_id,User_id:User_id},
dataType: 'json',
success:function(data)
{
var ParsedObject = JSON.stringify(data);
var json = $.parseJSON(ParsedObject);
$.each(json, function (key, data) {
var likes=data.type;
// alert(likes);
var count=likes.length;
alert(count);
// var post_id=data.post_id;
// $post_id=post_id;
// // alert(comment);
// // // alert(post_id);
// // var div_list=document.getElementById('#comment_div').innerHTML='post_id;
// // $("#comment_post_id").attr('value',$post_id);
var mediaID ='.likes'+post_id;
$(mediaID).append(likes);
});
}
});
}
controller
public function select_likes()
{
$Post_id=$this->input->post('Post_id');
$User_id=$this->input->post('User_id');
$this->load->model('Pmodel');
$select_likes=$this->Pmodel->select_likes_post_id($Post_id,$User_id);
// print_r($select_likes);
echo json_encode($select_likes);
}
model
public function select_likes_post_id($Post_id,$User_id)
{
$this->db->select('*');
$this->db->from('userpost_likes_share');
$this->db->where('post_id',$Post_id);
$this->db->where('type','like');
$query=$this->db->get();
$likes=$query->result_array();
return $likes;
}
but how can i count it ? is it possible to count no of times a variable calls in javscript
simply use count() function on $select_likes in controller count($select_likes) ... it will be the number of like on the post and pass it as json as json_encode(array('like_count'=>$like_count))
So in controller code can be like:
public function select_likes()
{
$Post_id=$this->input->post('Post_id');
$User_id=$this->input->post('User_id');
$this->load->model('Pmodel');
$select_likes=$this->Pmodel->select_likes_post_id($Post_id,$User_id);
$like_count = count($select_likes);
echo json_encode(array('like_count'=>$like_count));
}
Use in js script you can use the data.like_count as total number of like on the post.
If you only need like count from table then i would suggest only select one column from your 'userpost_likes_share' table.. you can select only id(primary key) of the table for make the code work faster.
Let me know if you think i get wrong and answer in wrong direction...

jQuery each loop variable data lost [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 7 years ago.
having a little trouble with my variable scope in jQuery, how come if I do the console.log outside the .each loop I get an empty array on $stockData ? (if i do it inside the .each, it works just fine, logs the array each time a value is added)
$(document).ready(function(){
// stock data will contain all the merged data from the database and yahoo queries
var $stockData = new Array();
// get data from yahoo and merge with dbData, add to stockData array
$.getJSON( "/get_portfolio.php", function(dbData) {
$.each( dbData, function(index) {
var stock = dbData[index]
$.ajax({
url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%3D%22"+stock.stock_symbol+"%22&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys",
crossDomain: true
}).success(function(data){
var quote = data.query.results.quote;
$.extend(quote, stock);
$stockData.push(quote);
}); // end success
});// end each
}); // end getJSON
console.log($stockData);
}); // end document.ready
when you call
$.getJSON( "/get_portfolio.php", function(dbData) { ... });
this part:
function(dbData) { ... }
doesn't run right away. JavaScript says: "oh you did a http request? I'll hold onto this function you gave me and run it after the request is done". And the rest of your code will keep on running, so this:
console.log($stockData);
will run first. So the actual order of execution here is:
you run getJSON
console.log runs
the HTTP request finishes and your callback runs
put the console.log inside the getJSON block, right after your .each loop:
$(document).ready(function(){
// stock data will contain all the merged data from the database and yahoo queries
var $stockData = new Array();
// get data from yahoo and merge with dbData, add to stockData array
$.getJSON( "/get_portfolio.php", function(dbData) {
var requestsDone = 0;
$.each( dbData, function(index) {
var stock = dbData[index]
$.ajax({
url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%3D%22"+stock.stock_symbol+"%22&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys",
crossDomain: true
}).success(function(data){
var quote = data.query.results.quote;
$.extend(quote, stock);
$stockData.push(quote);
if(++requestsDone == dbData.length) done();
}).error(function(){
if(++requestsDone == dbData.length) done();
});
});// end each
function done() {
console.log($stockData); // put this here
}
}); // end getJSON
}); // end document.ready
You need to wait getJSON function be completed, try this:
$(document).ready(function(){
// stock data will contain all the merged data from our database and yahoo queries
var $stockData = new Array();
// get data from yahoo and merge with dbData, add to stockData array
$.getJSON( "/get_portfolio.php", function(dbData) {
$.each( dbData, function(index) {
var stock = dbData[index]
$.ajax({
url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%3D%22"+stock.stock_symbol+"%22&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys",
crossDomain: true
}).success(function(data){
var quote = data.query.results.quote;
$.extend(quote, stock);
$stockData.push(quote);
}); // end success
});// end each
console.log($stockData);
}); // end getJSON
});

How to display array content at the end of getjson call?

i have a function that makes 2 getjson calls and writes the responses to an array . i used the following code at the end of my second getjson call:
alert(files.length);
print_r(files);
console.log(files);
However , the files.length tells me the number of items in the array but print_r(files); and console.log are not working ? i want to print the array items to confirm i got correct items but array print doesn't work ! could any one tell me how to fix this problem ?( my goal is to later on sort this array and remove duplicates and filter... )
<script>
var files = new Array();
function pushtoArray(){
//first getjson call
var url1 = "https://spreadsheets.google.com/feeds/list/xxxxx/xxxxx/public/values?alt=json";
$.getJSON(url1, function(data) {
var entry = data.feed.entry;
$(entry).each(function(){
// Column names are name, age, etc.
count++;
files.push({ url: this.gsx$url.$t, filename: this.gsx$name.$t });
$('.results').prepend('<h2>'+this.gsx$name.$t+'</h2><p>'+this.gsx$url.$t+'</p>');
});
alert(files.length);
print_r(files);
console.log(files);
});//end of ajax call
//second getjson call
var url2 = "https://spreadsheets.google.com/feeds/list/xxxxx/xxxxx/public/values?alt=json";
$.getJSON(url2, function(data) {
var entry = data.feed.entry;
$(entry).each(function(){
// Column names are name, age, etc.
count++;
files.push({ url: this.gsx$url.$t, filename: this.gsx$name.$t });
$('.results').prepend('<h2>'+this.gsx$name.$t+'</h2><p>'+this.gsx$url.$t+'</p>');
});
alert(files.length);
print_r(files);
console.log(files);
});//end of ajax call
};//end of function
</javascript>
html code:
<body onload="pushtoArray()">
Print_r is a PHP function, in javascript you can only use console.log.

Updating a list with ajax response data in a specific order

I have an ajax request that gets called several times based on the number of request objects in an array. The order in which these objects are in inside of the array is important, and needs to be reflected in a dynamically generated list in that same order. When the server sends back each response I update a <ul> as shown below.
$.ajax({
type: 'POST',
url: baseServiceURL + 'report/',
processData: false,
dataType: 'json',
contentType: 'application/json',
data: payload,
crossDomain: true,
})
.done(function (response) {
updateUI(response);
})
.fail(function (jqXHR, textStatus) {
// handle failure
});
var updateUI = function (response) {
// Update the drop-down list
$('#dropdown').append('<li><a class="dd-option" data-value="' + response.ReportName + '" data-path="' + response.ReturnURL + '" href="#">' + response.ReportName + '</a></li>');
// do more stuf...
};
How can I dynamically build the list in such a way to where the response display in the proper order? One thing I have done is add a order param to the request who's value is the index of the request object in the array. My thought is my service can send that value back in the response so the javascript can act on it.
EDIT: The question here is asking basically the same thing except rather than using a getJSON command and appending divs I'm using a post and appending <li> elements.
There are two possible strategies here.
Update your UI immediately upon receiving response and then re-render if a new value is received
Wait until all ajax replies have finished and then render your UI
For (1) you should just keep a running total of all items
var $dropdown = $('#dropdown');
var renderDropdown = function(reports) {
//use lodash or underscore.js here cause implementing this manually is annoying
var sortedSelections = _.sortBy(reports, 'order');
var htmlPerItem = sortedSelections.map(function(item) {
return '<li><a ..... </li>';
});
$dropdown.html(htmlPerItem.join(''));
}
var reportSelections = [];
payloads.map(function(payload) {
$.ajax({ ... })
.then(function(response) {
reportSelections.push(response);
renderDropdown(reportSelections);
})
})
for (2) you can use jquery $.when
var gettingResults = payloads.map(function(payload) {
return $.ajax({ .... });
});
$.when(gettingResults).then(function() {
//the first arg will be response1, the second response2, etc
var reportSelections = _.sortBy(arguments, 'order');
renderDropdown(reportSelections);
});
Note in (1) you render once per item but get an updating view as items come in. In (2) you render only once but have to wait until all loading is complete.
Of course a variation of (1) is that you don't re-render anything, but merely insert items into the correct location as they are loaded. That's going to be more difficult to debug and more code so I leave it as an exercise for the reader (use jquery's $.fn.data to store the original item with the element).

Categories