I am currently making an autocomplete function that retrieves a bunch of information encoded by JSON and allows the user to search through it. There is a slight delay in the search results, and I think that a for loop inside of another for loop is the cause of this issue. Below is the Javascript file:
var username = [];
var businessname = [];
var fname = [];
var lname = [];
var fullname = [];
var clientid = [];
var bankArray = [];
var data_for_post = [];
var focusedArrayElement = "";
var started = false;
var currentSelectedList = 0;
var searchString = "";
$(document).keydown(function(event) {
switch(event.keyCode) {
case 40:
if (!$("#results li:first").hasClass("selected") && !started) {
$("#results li:first").addClass("selected");
started = true;
} else {
if($("#results li.selected").next().length > 0) {
$("#results li.selected").next().addClass("selected");
$("#results li.selected:first").removeClass("selected");
}
}
assign = $(".selected").text();
$(".autocomplete").val(assign);
break;
case 38:
$("#results li.selected").prev().addClass("selected");
$("#results li.selected:last").removeClass("selected");
if(!$("#results").siblings('.selected').length > 0) {
started = false;
}
assign = $(".selected").text();
$(".autocomplete").val(assign);
break;
case 13:
assign = $(".selected").text();
console.log(assign);
$("#results").empty();
$("#inner").text(assign);
break;
}
});
$(document).ready(function() {
$.ajax({
type: "GET",
dataType: "json",
url: "autocomplete.php?search=1",
success: function(data) {
$.each(data.client, function(key, value) {
username.push(value.username);
businessname.push(value.businessname);
fname.push(value.fname);
lname.push(value.lname);
clientid.push(value.clientid);
for(var i = 0; i < fname.length; i++) {
fullname[i] = fname[i] + " " + lname[i];
}
});
bankArray = [username, businessname, fullname, clientid];
console.log(bankArray);
}
});
$(".autocomplete").on("keyup change", function(e) {
console.log(e.keyCode);
if(e.keyCode != 38 && e.keyCode != 40) {
$("#results").empty();
}
currentSearchString = $(".autocomplete").val();
if(currentSearchString) {
//$("#results").css('border-top', '1px solid black');
for(var i = 0; i < bankArray.length; i++) {
for(var j = 0; j < bankArray[i].length; j++) {
focusedArrayElement = bankArray[i][j].toLowerCase();
usernames = bankArray[0];
businessnames = bankArray[2];
fullnames = bankArray[3];
if(focusedArrayElement.indexOf(currentSearchString.toLowerCase()) > -1) {
focused_businessname = bankArray[1][j];
focused_fullname = bankArray[2][j];
focused_clientid = bankArray[3][j];
postedData = focused_fullname + " -- " + focused_businessname;
if (!$(".clientid." + focused_clientid).length) {
$("#results").append("<li id='" + (j + 1) + "' class='clientid " + focused_clientid + "'>" + postedData + "</li>");
}
}
}
}
}
else {
$("#results").empty();
started = false;
}
});
});
The basic principle is that when the document readies, an ajax call pushes all of the JSON data into a multidimensional array with different categories of information. From here, a first for loop searches through each array in the bankArray, and the second searches through each element of the current array. If the current search string in the input field matches the focused element from the array, it appends that information to a div below.
I feel as if the code is inefficient in how it deals with the JSON data and checks through it. If anyone has any suggestions on how to optimize the code, that would be great.
Related
I have created my table with jQuery and have it using filtering on the column. However, ran into something interesting.
Below is my fiddle
https://jsfiddle.net/4sy5dweg/1/
So my issue is as follows -
Once I find what I am looking for by filtering. If I decided to start backspacing I want it to continue searching that column and obviously start going backwards on searching.
I hope that makes sense.
$.extend($.expr[":"], {
"containsIN": function (elem, i, match, array) {
return (elem.textContent || elem.innerText || "").toLowerCase().indexOf((match[3] || "").toLowerCase()) >= 0;
}
});
$("[id*=TXTSEARCH]").keyup(function () {
tablename = $(this).closest('table').attr('id');
mytd = $(this).closest('th');
var indexColumn = mytd.index();
var data = this.value.toLowerCase().split(" ");
var jo = $("[id*=" + tablename + "]").find("tr:not(:first)");
jo.filter(function (i, v) {
var $t = $(this).children(":eq(" + indexColumn + ")");
for (var d = 0; d < data.length; ++d) {
if ($t.is(":not(:containsIN('" + data[d] + "'))")) {
console.log(data[d]);
return true;
}
}
return false;
}).hide();
})
I know the issue has to do with hiding that row on initial search. However, somehow for isntance if someone has a typo and goes to backspace it wont show anything because that row is still hidden. Is there a way to keep the other filters in place and basically remove the filter from the row being corrected?
I hope I am making sense.
Update I have attempted the following -
$("[id*=TXTSEARCH]").keyup(function () {
var tablename = $(this).closest('table').attr('id');
console.log(tablename);
var FindMyRow;
$("#" + tablename).find('th:visible').find($("[id*=TXTSEARCH]")).each(function () {
FindMyRow = $(this).closest('th:visible');
var indexColumn = FindMyRow.index();
console.log($(this).attr('id') + " " + indexColumn);
var data = this.value.toLowerCase().split(" ");
var jo = $("[id*=" + tablename + "]").find("tr:not(:first)");
jo.show().filter(function (i, v) {
var $t = $(this).children(":eq(" + indexColumn + ")");
for (var d = 0; d < data.length; ++d) {
if ($t.is(":not(:containsIN('" + data[d] + "'))")) {
console.log(data[d]);
return true;
}
}
return false;
}).hide();
});
to no avail.
Decided to change my way of doing it.
I added a button to each column header that the user can click on so that if they make a type they just check it before clicking it.
$("[id*=BTNSEARCH]").click(function (e) {
e.preventDefault();
var tablename = $(this).closest('table').attr('id');
mytd = $(this).closest('th');
var TextBoxToSearch = ($(this).prev('input').val());
var indexColumn = mytd.index();
FindMyRow = $(this).closest('th:visible');
var indexColumn = FindMyRow.index();
var data = TextBoxToSearch.toLowerCase().split(" ");
var jo = $("#" + tablename).find("tr:not(:first)");
jo.filter(function (i, v) {
var $t = $(this).children(":eq(" + indexColumn + ")");
for (var d = 0; d < data.length; ++d) {
if ($t.is(":not(:containsIN('" + data[d] + "'))")) {
return true;
}
}
return false;
}).hide();
})
I have a CSV file with ~20,000 records. I send each line using the $.post method to my server using the FileReader API.
The problem is that the browser is buffering each record before starting to send the data and this way is very slow. I want to send each line separately to show a progressbar where it counts the request number of each line.
As this solution is very slow I'm thinking there are must be other ways of doing this to make it faster. Many thanks to your ideas.
$("#form_file").change(function(e) {
if (e.target.files != undefined) {
var reader = new FileReader();
reader.onload = function(e) {
var rows = e.target.result.split("\n");
var index = rows[0];
index = index.split(";");
gesamt = rows.length - 1;
for (var i = 1; i < rows.length; i++) {
var row = rows[i];
cells = row.split(";");
var dataset = {};
for (var ii = 0; ii < cells.length; ii++) {
var value = cells[ii];
var key = index[ii]
var printError = function(error, explicit) {
console.log(`[${explicit ? 'EXPLICIT' : 'INEXPLICIT'}] ${error.name}: ${error.message}`);
}
try {
dataset[key] = value;
} catch (e) {
if (e instanceof RangeError) {
if (e.message.toLowerCase().indexOf('invalid array') !== -1) {
printError(e, true);
} else {
printError(e, false);
}
} else {
printError(e, false);
}
}
}
console.log(dataset);
row = insertrow(dataset, i);
$('#progressbar').show();
$('#progressvalue').text(i + '/' + gesamt);
$('#progresstitle').text('(' + dataset.title + ')');
}
};
var test = reader.readAsText(e.target.files.item(0));
}
});
function insertrow(mydata, step) {
var token = "{{app.request.query.get('_token')}}";
mydata = JSON.stringify(mydata);
$.post('preferences/upload?_token=' + token, {
data: mydata
}, function(data) {
$('#info').show();
var html = data.message + '<br />';
$('#info').append(html);
}, "json");
}
I'm trying to get page speed score for both: desktop and mobile and then pass them to #pgscore && #pgscorem inputs.
Problem is that at the end of script I get always var device == 'mobile'. It looks like it skips for loop. Any idea how could I fix it?
for (var r = 0; r < 2; r++) {
var API_KEY = 'mykey';
var device = '';
switch (r) {
case 0: device='desktop'; break;
case 1: device='mobile'; break;
};
alert(device);
var URL_TO_GET_RESULTS_FOR = 'http://www.stackoverflow.com' + '&strategy=' + device;
var API_URL = 'https://www.googleapis.com/pagespeedonline/v1/runPagespeed?';
var CHART_API_URL = 'http://chart.apis.google.com/chart?';
var callbacks = {}
function runPagespeed() {
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
var query = [
'url=' + URL_TO_GET_RESULTS_FOR,
'callback=runPagespeedCallbacks',
'key=' + API_KEY,
].join('&');
s.src = API_URL + query;
document.head.insertBefore(s, null);
}
function runPagespeedCallbacks(result) {
if (result.error) {
var errors = result.error.errors;
for (var i = 0, len = errors.length; i < len; ++i) {
if (errors[i].reason == 'badRequest' && API_KEY == 'yourAPIKey') {
alert('Please specify your Google API key in the API_KEY variable.');
} else {
alert(errors[i].message);
}
}
return;
}
for (var fn in callbacks) {
var f = callbacks[fn];
if (typeof f == 'function') {
callbacks[fn](result);
}
}
}
setTimeout(runPagespeed, 0);
callbacks.displayPageSpeedScore = function(result) {
var score = result.score;
Function countinues down there. Problem is here... Why I can't get variable device == 'desktop' first and then in second for loop 'mobile'? I get always 'mobile'.
switch (device) {
case 'desktop': $('#pgscore').val(score); break;
case 'mobile': $('#pgscorem').val(score); break;
};
};
};
Since I need only score, I'm using php
$jsonurl="https://www.googleapis.com/pagespeedonline/v1/runPagespeed?url=$url&locale=pl_pl&$key";
$json = file_get_contents($jsonurl);
$json_output = json_decode($json, true);
/* print_r(array_values($json_output));*/
echo $json_output['score'];
I have created a related post javascript for blogger.com based blogs. The related post plugins loops though the label attached to the current post and displays other posts with the same label.
You can find that in action # http://www.techquark.com/2017/07/infocus-turbo-5-affordable-powerful.html
The issue is I want to skip the current post to be shown in the related post, but unable to achieve the same.
PFB the javascript code :
$(".related-ready").each(function() {
var b = $(this).text();
$.ajax({
url: "/feeds/posts/default/-/" + b + "?alt=json-in-script&max-results=3",
type: 'get',
dataType: "jsonp",
success: function(e) {
var u = "";
var h = '<div class="related">';
for (var i = 0; i < e.feed.entry.length; i++) {
for (var j = 0; j < e.feed.entry[i].link.length; j++) {
if (e.feed.entry[i].link[j].rel == "alternate") {
u = e.feed.entry[i].link[j].href;
break
}
}
var g = e.feed.entry[i].title.$t;
var c = e.feed.entry[i].content.$t;
var $c = $('<div>').html(c);
if (c.indexOf("//www.youtube.com/embed/") > -1) {
var p = e.feed.entry[i].media$thumbnail.url;
var k = p
} else if (c.indexOf("<img") > -1) {
var q = $c.find('img:first').attr('src');
var k = q
} else {
var k = NO_IMAGE
}
h += '<li><div class="related-thumb"><a class="related-img" href="' + u + '" style="background:url(' + k + ') no-repeat center center;background-size: cover"/></div><h3 class="related-title">' + g + '</h3></li>'
}
h += '</div><div class="clear"/>';
$(".related-ready").html(h);
$('.related-img').each(function() {
$(this).attr('style', function(i, src) {
return src.replace('/default.jpg', '/hqdefault.jpg')
}).attr('style', function(i, src) {
return src.replace('s72-c', 's1600')
})
})
}
})
});
TIA !
You will need to check whether the current Post's ID matches with the ID of the post in feed and then skip that post, the code will look like -
....
for (var i = 0; i < e.feed.entry.length; i++) {
if(e.feed.entry[i].id.$t.split("post-")[1] === "<data:post.id/>"){
break;
}
for (var j = 0; j < e.feed.entry[i].link.length; j++) {
....
Is there a way for the JQGrid to return an array of column Data for using multiSelect as opposed to just an array of rowIds ?
At the moment I can only return the last column data that was selected.
jQuery("#buttonSelected").click(function() {
var ids = jQuery("#relatedSearchGrid").getGridParam('selarrrow');
var count = ids.length;
for (var i = 0; i < count; i++) {
var columnData = $("#relatedSearchGrid").find("tbody")[0].rows[$("#relatedSearchGrid").getGridParam('selrow') - 1].cells[1].innerHTML;
alert("In the loop and " + columnData );
}
if (count == 0) return;
var posturl = '<%= ResolveUrl("~") %>Rel******/AddSelected****/' + ids;
if (confirm("Add these " + count + " Docs?")) {
$.post(posturl,
{ ids: columnData },
function() { jQuery("#relatedSearchGrid").trigger("reloadGrid") },
"json");
}
})
Use getRowData to get the data for each row:
var rowData = $("#relatedSearchGrid").getRowData(ids[i]);
var colData = rowData.Name_Of_Your_Column;
var userListjqGrid = $('#UserListGrid'),
selRowId = userListjqGrid.jqGrid('getGridParam', 'selrow'),
userId = userListjqGrid.jqGrid('getCell', selRowId, 'UserId'),
userName = userListjqGrid.jqGrid('getCell', selRowId, 'UserName'),
subIds = $(subgridTableId).getGridParam('selarrrow'),
accessRuleIds = [];
for (var i = 0; i < subIds.length; i++) {
accessRuleIds[i] = $(subgridTableId).getRowData(subIds[i]).AccessRuleId;
}