What can I do to avoid Syncronous AJAX Request - javascript

I have this Array
var testFlows = ["test1","test2","test3","test4","test5"];
I'm trying to get the inputs one by one and generating some html (the html generated doesn't really matter).
What matters is that I want to see this html panels by the order of the testFlows array. My code is completely random. If I refresh the page they are on different positions.
One solution would be to make a synchronous ajax but it's deprecated and bad, so what else can I do?
Code:
var testFlows = ["test1","test2","test3","test4","test5"];
$.each(testFlows, function (index, testFlow) {
//get the inputs
$.ajax({
url: '/flow/getInputs',
type: 'post',
data: {testCaseName: testFlow.testCase.name},
success: function (inputNames) {
testCaseAccordion = '<div class="panel panel-default"><div class="panel-heading"><h4 class="panel-title"><a class="collapseTitle" data-toggle="collapse" data-parent="#accordion" href="#collapse-' + testFlow.testCase.name + index + '">' + testFlow.testCase.name + '(' + testFlow.testCase.type.name + ') <span id="eyeIcon" class="fas fa-eye float-right"></span></a></h4></div>';
testCaseAccordion += '<div id="collapse-' + testFlow.testCase.name + index + '" class="panel-collapse collapse"><div id="panel-body-' + testFlow.testCase.name + index + '" class="panel-body"></div></div>';
$('#accordion').append(testCaseAccordion);
if (testFlow.params !== null) {
var inputs = testFlow.params.split(',');
for (var i = 0; i < inputs.length; i++) {
$('#panel-body-' + testFlow.testCase.name + index).append('<strong class="color-red">' + inputNames[i] + ': </strong>' + inputs[i] + '<br>');
}
}
else {
$('#panel-body-' + testFlow.testCase.name + index).append("This test case doesn't have any inputs");
}
}
});
});

You can use promises, for example, in your case:
var testFlows = ["test1","test2","test3","test4","test5"];
function success(testFlowAndInputNames, index) {
var testFlow = testFlowAndInputNames[0];
var inputNames = testFlowAndInputNames[1];
var testCaseAccordion = '<div class="panel panel-default"><div class="panel-heading"><h4 class="panel-title"><a class="collapseTitle" data-toggle="collapse" data-parent="#accordion" href="#collapse-' + testFlow.testCase.name + index + '">' + testFlow.testCase.name + '(' + testFlow.testCase.type.name + ') <span id="eyeIcon" class="fas fa-eye float-right"></span></a></h4></div>';
testCaseAccordion += '<div id="collapse-' + testFlow.testCase.name + index + '" class="panel-collapse collapse"><div id="panel-body-' + testFlow.testCase.name + index + '" class="panel-body"></div></div>';
$('#accordion').append(testCaseAccordion);
if (testFlow.params !== null) {
var inputs = testFlow.params.split(',');
for (var i = 0; i < inputs.length; i++) {
$('#panel-body-' + testFlow.testCase.name + index).append('<strong class="color-red">' + inputNames[i] + ': </strong>' + inputs[i] + '<br>');
}
}
else {
$('#panel-body-' + testFlow.testCase.name + index).append("This test case doesn't have any inputs");
}
}
var arrayOfPromises = testFlows.map(function (testFlow) {
return new Promise(function (resolve, reject) {
$.ajax({
url: '/flow/getInputs',
type: 'post',
data: {testCaseName: testFlow.testCase.name},
success: resolve
});
})
.then(function(inputNames) {
return [testFlow, inputNames];
})
});
Promise.all(arrayOfPromises)
.then(function(results) {
results.forEach(success)
});

jQuery ajax returns a promise, so you could save all the promises into an array, eg:
var testFlows = ["test1", "test2", "test3", "test4", "test5"];
var testFlowsPromises = $.map(testFlows, function(testFlow, index) {
//get the inputs
return $.ajax({
url: '/flow/getInputs',
type: 'post',
data: {testCaseName: testFlow.testCase.name}
}).then(function(inputNames) {
return {
inputNames: inputNames,
testFlow: testFlow
};
});
});
Then, wait until all of them are done:
$.when.apply($, testFlowsPromises).done(function() {
$.each(arguments, function(index, data) {
// do stuff with index, data.inputNames, data.testFlow
});
});
Now you'd have an array of ajax data in the same order.
DEMO:
https://jsbin.com/fixuxezale/edit?js,console

Related

How to pass an array data from controller to blade file Laravel

I'm trying to pass an array from Controller to Blade
My Controller:
public function socaucuachuong($id){
$socaucuachuong = CauHoi::groupBy('chuong')->select('chuong', CauHoi::raw('count(id) as Total'))->where('idmonthi','=', $id)->get()->toArray();
return view('DeThi::dethi')->with('socaucuachuong', $socaucuachuong);
}
My Blade file:
$('select').select();
function get_units(id) {
var list = $('#dschuong');
list.empty();
var url = "{{ route('dethi.socaucuachuong') }}"+'/'+ id;
var success = function (result) {
if (result.length <= 0) {
var item = '<div class="input-field"><input type="text" disabled value="Môn này hiện chưa có câu hỏi nào"></div>';
list.append(item);
} else {
for (i = 0; i < result.length; i++) {
var item = '<div class="input-field"><label for="unit-' + result[i].chuong + '">Nhập số câu hỏi chương ' + result[i].chuong + ' (có ' + result[i].Total + ' câu) <span class="failed">(*)</span></label><input type="number" max="' + result[i].Total + '" class="unit_input" onchange="set_sum(' + result[i].Total + ')" name="unit-' + result[i].chuong + '" id="unit-' + result[i].chuong + '" required></div>';
list.append(item);
}
}
};
$.get(url, success);
}
My Route file:
Route::post('socaucuachuong', 'DeThiController#socaucuachuong')->name('dethi.socaucuachuong');
You can get array values in blade like this.
<script>
var socaucuachuong = #JSON($socaucuachuong); // this will be array value.
</script>

Clear previous results from query

Through the attached code I do a search on youtube based on the username and the results are shown. If I search twice, the results add up. I would like previous results to be deleted. I try with htmlString = card; but it show only one result.Thanks to everyone who wants to help me solve this problem.
var musicCards = [];
jQuery(document).ready(function() {
jQuery("#searchButton").on("click", function() {
var query = jQuery("#queryInput").val();
if (query != "") {
loadYoutubeService(query);
console.log(query + "");
}
});
});
function loadYoutubeService(query) {
gapi.client.load('youtube', 'v3', function() {
gapi.client.setApiKey('ADADADADADA');
search(query);
});
}
function search(query) {
var request = gapi.client.youtube.search.list({
part: 'snippet',
q: query,
type: 'channel',
maxResults: 15
});
request.execute(function(response) {
jQuery.each(response.items, function(i, item) {
if (!item['']) {
var musicCard = {};
musicCard._id = item['snippet']['customUrl'];
musicCard.title = item['snippet']['title'];
musicCard.linkprofilo = item['snippet']['channelId'];
musicCard.url = "https://www.youtube.com/channel/";
musicCard.description = item['snippet']['description'];
musicCard.immagine = item['snippet']['thumbnails']['high']['url'];
musicCards.push(musicCard);
}
});
renderView();
});
}
function renderView() {
var htmlString = "";
musicCards.forEach(function(musicCard, i) {
var card = createCard(musicCard._id, musicCard.title, musicCard.description, musicCard.url,musicCard.immagine, musicCard.linkprofilo);
htmlString += card;
});
jQuery('#youtube-utente').html(htmlString);
}
function createCard(_id, title, description, url, immagine, linkprofilo) {
var card =
'<div class="card">' +
'<div class="info">' +
'<img src="' + immagine + '" alt="' + description + '">' +
'</div>' +
'<div class="content">Clicca per selezionare:' +
'<h3>' + title + '</h3>' +
'<a class="seleziona" href="' + url +linkprofilo+'">'+ url +linkprofilo+'</a>' +
'<p>' + description + '</p>' +
'</div>' +
'</div>';
return card;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
Solved using :
request.execute(function(response) {
musicCards.length = 0; // clear array

I have javascript code to view a news from RSS as a vertical list. I need help to move the list of topics as horizontal one by one, in one line

I have javascript code to view a news from RSS as a vertical list.
(function ($) {
$.fn.FeedEk = function (opt) {
var def = $.extend({
MaxCount: 5,
ShowDesc: true,
ShowPubDate: true,
DescCharacterLimit: 0,
TitleLinkTarget: "_blank",
DateFormat: "",
DateFormatLang:"en"
}, opt);
var id = $(this).attr("id"), i, s = "", dt;
$("#" + id).empty();
if (def.FeedUrl == undefined) return;
$("#" + id).append('<img src="loader.gif" />');
var YQLstr = 'SELECT channel.item FROM feednormalizer WHERE output="rss_2.0" AND url ="' + def.FeedUrl + '" LIMIT ' + def.MaxCount;
$.ajax({
url: "https://query.yahooapis.com/v1/public/yql?q=" + encodeURIComponent(YQLstr) + "&format=json&diagnostics=false&callback=?",
dataType: "json",
success: function (data) {
$("#" + id).empty();
if (!(data.query.results.rss instanceof Array)) {
data.query.results.rss = [data.query.results.rss];
}
$.each(data.query.results.rss, function (e, itm) {
s += '<li><div class="itemTitle"><a href="' + itm.channel.item.link + '" target="' + def.TitleLinkTarget + '" >' + itm.channel.item.title + '</a></div>';
if (def.ShowPubDate){
dt = new Date(itm.channel.item.pubDate);
s += '<div class="itemDate">';
if ($.trim(def.DateFormat).length > 0) {
try {
moment.lang(def.DateFormatLang);
s += moment(dt).format(def.DateFormat);
}
catch (e){s += dt.toLocaleDateString();}
}
else {
s += dt.toLocaleDateString();
}
s += '</div>';
}
if (def.ShowDesc) {
s += '<div class="itemContent">';
if (def.DescCharacterLimit > 0 && itm.channel.item.description.length > def.DescCharacterLimit) {
s += itm.channel.item.description.substring(0, def.DescCharacterLimit) + '...';
}
else {
s += itm.channel.item.description;
}
s += '</div>';
}
});
$("#" + id).append('<ul class="feedEkList">' + s + '</ul>');
}
});
};
})(jQuery);
I need help to move the list of topics as horizontal one by one, in one line. by used javascript code. this code display just 5 topics, which I need it, but I have problem to how can I movement it as horizontal.

How to convert the values in an array to strings and send to php?

I have a javascript file here.What it does is,when a user selects seats accordings to his preference in a theater layout,the selected seats are stored in an array named "seat".This code works fine until function where the selected seats are shown in a window alert.But from there onwards,the code doesn't seem to do anything.
After the above window alert, I've tried to serialize the above array and send it to the "confirm.php" file.But it does not show anything when echoed the seats.
Here is the js code.
<script type="text/javascript">
$(function () {
var settings = {
rows: 6,
cols: 15,
rowCssPrefix: 'row-',
colCssPrefix: 'col-',
seatWidth: 80,
seatHeight: 80,
seatCss: 'seat',
selectedSeatCss: 'selectedSeat',
selectingSeatCss: 'selectingSeat'
};
var init = function (reservedSeat) {
var seat = [], seatNo, className;
for (i = 0; i < settings.rows; i++) {
for (j = 0; j < settings.cols; j++) {
seatNo = (i + j * settings.rows + 1);
className = settings.seatCss + ' ' + settings.rowCssPrefix + i.toString() + ' ' + settings.colCssPrefix + j.toString();
if ($.isArray(reservedSeat) && $.inArray(seatNo, reservedSeat) != -1) {
className += ' ' + settings.selectedSeatCss;
}
seat.push('<li class="' + className + '"' +
'style="top:' + (i * settings.seatHeight).toString() + 'px;left:' + (j * settings.seatWidth).toString() + 'px">' +
'<a title="' + seatNo + '">' + seatNo + '</a>' +
'</li>');
}
}
$('#place').html(seat.join(''));
};
var jArray = <?= json_encode($seats) ?>;
init(jArray);
$('.' + settings.seatCss).click(function () {
if ($(this).hasClass(settings.selectedSeatCss)) {
alert('This seat is already reserved!');
} else {
$(this).toggleClass(settings.selectingSeatCss);
}
});
$('#btnShowNew').click(function () {
var seat = [], item;
$.each($('#place li.' + settings.selectingSeatCss + ' a'), function (index, value) {
item = $(this).attr('title');
seat.push(item);
});
window.alert(seat);
});
$('#btnsubmit').click(function () {
var seat = [], item;
$.each($('#place li.' + settings.selectingSeatCss + ' a'), function (index, value) {
item = $(this).attr('title');
seat.push(item);
var seatar = JSON.stringify(seat);
$.ajax({
method: "POST",
url: "confirm.php",
data: {data: seatar}
});
});
});
});
</script>
Can somebody help me figure it out what's wrong in here?
Please Add content type as json.
$.ajax({
method: "POST",
url: "confirm.php",
contentType: "application/json"
data: {data: seatar}
});
For testing you can print file_get_contents('php://input') as this works regardless of content type.

ajax callback to insert image if exists

I've been following this answer in an attempt to write good asynchronous js - but I can't quite figure out what's going wrong for me.
I'm using autocomplete to request a specific set of files from the server, but for some datasets these files may not exist (i.e, there may be one, or up to four files). If they do exist, I want to append .html to include them.
The images don't load unless I add
async: false
to the .ajax call, which makes the callback redundant.
for (var i = 1; i < 5; i++) {
(function (counter) {
// define function with the callback argument
function ajaxTest(callback) {
$.ajax({
type: "GET",
url: counter + "_1.jpg",
success: function (result) {
callback(counter);
}
});
}
// call the function
ajaxTest(function (num) {
var image_temp = '<div class="thumbnail"> <img class="img-thumbnail" src="'+ num + '_1.jpg" /> Image' + num + '</div>';
console.log(image_temp); //check readout
image_html += image_temp;
});
})(i);
}
Then image_html contains html for only those images that exist.
$('#outputcontent').html(outer_html + image_html + outer_html_end);
Can anyone explain to my misunderstanding here please? Why isn't image_html being populated?
EDIT: 'full' code below. I use jquery autocomplete to pull from the stellar_comp array, then for those with properties that exist (some are blank), html is generated. Within that is the ajax call.
$(function () {
var stellar_comp = [
{
value:'X0005-28',
data: {
set0: {
aperture:'X2105-28',
secat:'X025-18',
set:'1',
run:'r06',
continuumFilter:'J',
narrowBandFilter:'638/28',
numberOfSources:'1',
priorityCode:'1'
etc... etc ...
},
},
];
$('#autocomplete').autocomplete({
lookup: stellar_comp,
onSelect: function (suggestion) {
var path_Value = 'data/' + suggestion.value + '/';
var outer_html = '<h1>' + suggestion.value + ' </h1> <div class="container">';
var outer_html_end = '</div>';
for (var category in suggestion.data) {
if (suggestion.data.hasOwnProperty(category)) {
if (suggestion.data[category].aperture) {
summary_table_contents = '<tr> <td>' + suggestion.data[category].set + '</td> <td>' + suggestion.data[category].run + '</td> <td>' + suggestion.data[category].continuumFilter + '</td> <td>' + suggestion.data[category].narrowBandFilter + '</td> <td>' + suggestion.data[category].numberOfSources + '</td> <td>' + suggestion.data[category].priorityCode + '</td></tr> ';
summary_table += summary_table_contents;
var aperturePlot = suggestion.data[category].aperture + '_' + suggestion.data[category].run;
var seCATPlot = suggestion.data[category].secat + '_Rsub_ss_' + suggestion.data[category].run;
var aperture_match = suggestion.data[category].aperture_match;
cog = path_Plots + aperturePlot + '_cog';
sbprof = path_Plots + aperturePlot + '_sbprof';
thumb_cog = '';
thumb_cog_temp = '';
thumb_sb = '';
temp='';
for (var i = 1; i < 5; i++) {
(function (counter) {
function some_function(callback) {
$.ajax({
type: "GET",
url: cog + counter + "_1.jpg",
async: false,
success: function (result) {
callback(counter);
}
});
}
some_function(function (num) {
var thumb_cog_temp = '<div class="col-lg-3 col-sm-4 col-xs-6"> <a class="thumbnail" target="_blank" href="' + cog + num + '_1.jpg"> <img class="img-thumbnail" src="' + cog + num + '_4.jpg" /></a> <div class="caption"><h5>' + suggestion.value + ':S' + num + '</h5></div></div>';
var thumb_sb_temp = '<div class="col-lg-3 col-sm-4 col-xs-6"> <a class="thumbnail" target="_blank" href="' + sbprof + num + '_1.jpg"><img class="img-thumbnail" src="' + sbprof + num + '_4.jpg" /></a><div class="caption"><h5>' + suggestion.value + ':S' + num + ' </h5></div></div>';
console.log(num, counter);
thumb_cog += thumb_cog_temp;
thumb_sb += thumb_sb_temp;
});
})(i);
}
cog_sbprofile_row='<div class="row"><h3>C o G</h3> ' + thumb_cog + '</div><div class="row"><h3>Profiles</h3> ' + thumb_sb + '</div>';
console.log(cog_sbprofile_row);
body_html += aperture_row;
body_html += seCAT_row;
body_html += aperture_match_row;
body_html += pixel_map_row;
body_html += skyprofile_row;
body_html += cog_sbprofile_row;
body_html += '<hr>';
};
};
};
top_html += summary_table + '</tbody> </table> </div></div> <hr>';
$('#outputcontent').html(outer_html + hipass_container + top_html + body_html + outer_html_end);
}
});
});
The current problem is due to using the resulting HTML string, before it has been created via multiple asynchronous calls. You need to either defer that operation until all loads are completed, or change the situation so it is not dependent on final completion (progressive loading looks busier anyway).
Personally I would simply insert placeholders for the images as you loop and insert each as they load. This way the order is retained. You can even do effects (fade etc) on each as they load:
var wrapper = "";
for (var i = 1; i < 5; i++) {
// Make a placeholder element for each image we expect
wrapper += '<div class="thumbnail" id="thumb_' + i + '">'
(function (num) {
// call the function
$.ajax({
type: "GET",
url: num + "_1.jpg",
success: function (result) {
var image_temp = '<img class="img-thumbnail" src="'+ num + '_1.jpg" /> Image' + num;
// Insert new image into unique element and fade it in
$('#thumb_'+num).append(image_temp).fadeIn();
}
});
})(i);
}
// Append all placeholders immediately - these will be appended to as each image is loaded
$('#outputcontent').html(outer_html + wrappers + outer_html_end);
Update:
As Alnitak points out, the whole exercise is a little pointless as you are ignoring the result returned from the Ajax call anyway, so you might as well drop the Ajax call (which adds no value) and simply build the image elements on the fly server-side :)
You have to do the appending after all ajax requests finish their jobs. First define this:
var after = function(reqs) {
var d = $.Deferred(),
cnt = reqs.length;
if (!cnt) {
d.resolve();
}
var limit = cnt; // separate var just in case reqs are synchronous
// so it won't mess up the loop
for (var i = 0; i < limit; i++) {
reqs[i].always(function() {
cnt--;
if (!cnt) {
d.resolve();
}
});
}
return d.promise();
};
You can use $.when instead of this but if one of the requests results in 404 it won't wait for others. Now:
var image_html = "",
requests = [];
for (var i = 1; i < 5; i++) {
(function (counter) {
// define function with the callback argument
function ajaxTest(callback) {
return $.ajax({
type: "GET",
url: counter + "_1.jpg",
success: function (result) {
callback(counter);
}
});
}
// call the function
var req = ajaxTest(function (num) {
var image_temp = '<div class="thumbnail"> <img class="img-thumbnail" src="'+ num + '_1.jpg" /> Image' + num + '</div>';
console.log(image_temp); //check readout
image_html += image_temp;
});
requests.push(req); // push the request to the array
})(i);
}
after(requests).done(function() {
$('#outputcontent').html(outer_html + image_html + outer_html_end);
});
Note that I've added return $.ajax(...).
BTW: what's the point of defining ajaxTest function? Just put everything in an anonymous callback.
Read more about deferred objects and promises here:
http://api.jquery.com/category/deferred-object/
http://joseoncode.com/2011/09/26/a-walkthrough-jquery-deferred-and-promise/
or just google it.
EDIT: if the order is important then you just have to tweak the callback function a bit:
var image_html = []; // array instead of string
// some code...
var req = ajaxTest(function (num) {
// ...
image_html[counter] = image_temp;
});
// some code...
after(requests).done(function() {
image_html = image_html.join("");
$('#outputcontent').html(outer_html + image_html + outer_html_end);
});

Categories