jQueryUI: Autocomplete with large data is hanging browser - javascript

I am using jQueryUI's autcomplete in my project. I have a autocomplete text where user search something and corresponding data comes in drop down.
With a small data set, it's working fine. The problem arises when the data set is large. I have almost 1L records with unique values which I've attach as source to autocomplete.
Now as soon as user enter search string in the text bar the browser hangs cause because of the processing that autocomplete of jQueryUI does.
I want to know how can I optimize it or make it faster so that the borwser does not hang. Here's the plunkr I have created to play. And this is what I am doing to attach source to autocomplete.
$("#tags").autocomplete({
source: availableTags
});

Instead of show all 50000 records show only top 10. Minimum search character length increased from default 0 to 2
$(function () {
var availableTags = [
"ActionScript",
"AppleScript",
"Asp",
"BASIC",
"C",
"C++",
"Clojure",
"COBOL",
"ColdFusion",
"Erlang",
"Fortran",
"Groovy",
"Haskell",
"Java",
"JavaScript",
"Lisp",
"Perl",
"PHP",
"Python",
"Ruby",
"Scala",
"Scheme"
];
for (var i = 0; i < 50000; i++) {
availableTags.push('abc' + i);
}
$("#tags").autocomplete({
minLength: 2,
source: function (request, response) {
var results = $.ui.autocomplete.filter(availableTags, request.term);
response(results.slice(0, 10));
}
});
});
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.0/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script>
<div class="ui-widget">
<label for="tags">Tags: </label>
<input id="tags">
</div>

Add a limit of displayed results, like ten.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jQuery UI Autocomplete - Default functionality</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.0/themes/base/jquery-ui.css">
<link rel="stylesheet" href="/resources/demos/style.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script>
<script>
$( function() {
var availableTags = [
"ActionScript",
"AppleScript",
"Asp",
"BASIC",
"C",
"C++",
"Clojure",
"COBOL",
"ColdFusion",
"Erlang",
"Fortran",
"Groovy",
"Haskell",
"Java",
"JavaScript",
"Lisp",
"Perl",
"PHP",
"Python",
"Ruby",
"Scala",
"Scheme"
];
var max= 10000;
// change max to 1000000 ie. 1L and it hangs.
for(var i=0;i<max;i++){
availableTags.push(i+'');
}
$("#tags").autocomplete({
source: function(request, response) {
var results = $.ui.autocomplete.filter(availableTags, request.term);
response(results.slice(0, 20));
}
});
} );
</script>
</head>
<body>
<div class="ui-widget">
<label for="tags">Tags: </label>
<input id="tags">
</div>
</body>
</html>
Please check this

I faced the same issue and solved the issue by overriding the _renderMenu function with a custom function that renders the itemlist asynchronously.
First you define an asynchronous rendering function AND a function to stop the asynchronous rendering (please read the API documentation, so you know what you are doing):
let customACFunctions = {
asyncRenderMenu: function(ul, data) {
let batchSize = 20;
let autoc = this; //refers to the autocomplete widget.
function renderNextBatch(){
$(ul).find('li.autocomplete-spinner').remove();
let j = 0;
while (j < batchSize && data.length > 0) {
autoc._renderItemData(ul, data.shift());
j++;
}
//normally, the widget internals add this class to each list item, now
//we'll have to do it ourselves
$(ul).find('li:not(.ui-menu-item)').addClass('ui-menu-item');
if (data.length > 0) {
//add an 'item' to indicate that the list is still being 'loaded'
$(ul).append('<li class="ui-menu-item autocomplete-spinner"><a>Laden...</a></li>');
customACFunctions._asyncRenderingTimeoutId = setTimeout(renderNextBatch, 1);
}
}
renderNextBatch();
},
_asyncRenderingTimeoutId: null,
stopAsyncRendering: function() {
if (customACFunctions._asyncRenderingTimeoutId) {
clearTimeout(customACFunctions._asyncRenderingTimeoutId);
customACFunctions._asyncRenderingTimeoutId = null;
}
}
};
Next, you will assign the asynchronous rendering function to the widget:
$("#autocompleteId").data("ui-autocomplete")._renderMenu = customACFunctions.asyncRenderMenu;
Next, we will also have to stop this asynchronous rendering - of which our widget is unaware - when we change the search query. (Otherwise you will get a mess in your item list...) If you have not defined an event handler for the 'search' event, you can do:
$("#autocompleteId").on("autocompletesearch", customACFunctions.stopAsyncRendering);
If you have defined an event handler for the search event, than invoke this function from that event handler.
And best is also to stop rendering when the user selects an item. If you have defined a function for the 'select' event, then invoke this function in your event handler. Otherwise:
$("#autocompleteId").on("autocompleteselect", customACFunctions.stopAsyncRendering);

I recommend to limit the data you fetch from somewhere other than local device.cause not displaying them does not mean you have not allotted memory for them. although doing so would help also.
P.s : apology for my poor english

Due to large volume of data set, some time this issue occurs. Browser get hang while loading large amount of data,
Here, first filter will work to slice a array and will return the decided accurate values from the whole data.
$("#postcode").autocomplete({
source: function (request, response){
var results = $.ui.autocomplete.filter(your_array,request.term);
response(results.slice(0, 10));
}
});
hope this will works for you

Related

How to do '#somename' like twitter functionality? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I am trying to do a functionality like which happens on Twitter.
If I write #J in text box, a list should appear show with autocomplete starting names "Javascript", "Java", "JQuery".
When I select Jquery, it should display in a TextBox. I got the autocomplete code from Jquery. But I am unable to do this '#' functionality.
Below is the code which I have done till now:
<html lang="en">
<head>
<meta charset="utf-8">
<title>autocomplete demo</title>
<link rel="stylesheet" href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
</head>
<body>
<label for="autocomplete">Select a programming language: </label>
<input id="autocomplete">
<script>
var tags = [ "Javascript", "Jquery", "Java" ];
document.getElementById('autocomplete').onkeypress = function (e) {
if (e.keyCode === 64 ) {
$( "#autocomplete" ).autocomplete({
source: function( request, response ) {
var matcher = new RegExp( "^" + $.ui.autocomplete.escapeRegex( request.term ), "i" );
response( $.grep( tags, function( item ){
return matcher.test( item );
}) );
}
});
}
else
{
return false;
}
};
</script>
</body>
</html>
Try this:
http://jsfiddle.net/gtnf41co/5/
It checks input value starts with #:
if (this.value.search("#") == 0)
then takes out the # in the request term
request.term.replace("#", "")
You can do this with the autocomplete functionality by adding the # symbol to your tags:
<script>
var tags = [ "#Javascript", "#Jquery", "#Java" ];
$( "#autocomplete" ).autocomplete({
source: tags
});
</script>

JSON data not returned from Azure blob storage query

I'm in the process of trying to create a quiz using JavaScript and JQuery. I'm storing the data for the quiz(questions, options) in Azure blob storage.
When the json is stored locally adn in the same folder and I use getJSON to make the call, it works. According to this thread, Query JSON data from Azure Blob Storage with jQuery, that won't work if the content is in Azure blob storage, but when I tried to make the modifications as described in thread, I get nothing. Any help is greatly appreciated. Below, I've included my HTML, JSON and JS.
HTML:
<!DOCTYPE HTML>
<head>
<title>HTML5 - Multiple Choose Quiz Sample</title>
<link href="main.css" rel="stylesheet" type="text/css"/>
<script src="jquery.js"></script>
<script src="controller.js"></script>
<script type="text/javascript" src="https://djmblob.blob.core.windows.net/quizzes/activity.json"></script>
<!--Adjust for mobile phones-->
<meta name=viewport content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
</head>
<body>
<!--comenting out for now...tes<div id="topbar">HTML5 MCQ Quiz</div>-->
<!--comenting out for now...<div class="spacer"></div>-->
<div id="navContent">
<div id="game1"></div>
<div id="game2"></div>
</div>
</body>
JSON:
dataCallback({"quizlist":[
{
"question":"Josh Hutcherson is known for his main role in the movie series The Hunger Games, but in what other movie was he the main character?",
"option1":"The Polar Express",
"option2":"John Tucker Must Die",
"option3":"The Alamo"
},
{
"question":"Who was the villain in Othello?",
"option1":"Iago",
"option2":"His Wife",
"option3":"Cassio"
},
{
"question":"What was Will Smith’s character Mike Lowery’s middle name in the movie series Bad Boys?",
"option1":"Eugene",
"option2":"Eric",
"option3":"Brian"
},
{
"question":"At the 2001 Academy Award, what movie won both the Best Picture and Best Actor in a Leading Role award?",
"option1":"Gladiator",
"option2":"Traffic",
"option3":"Erin Brockovich"
},
{
"question":"Who was the original killer in Friday the 13th?",
"option1":"Jason's mother",
"option2":"Freddy",
"option3":"Jason"
},
{
"question":"Who played the main female role in G.I. Jane?",
"option1":"Demi Moore",
"option2":"Megan Fox",
"option3":"Lucy Lu"
},
{
"question":"In what year was Dude, Who Stole My Car? released?",
"option1":"2000",
"option2":"2005",
"option3":"2014"
},
{
"question":"What character does Michael B. Jordan play in the 2015 Fantastic 4?",
"option1":"Human Torch",
"option2":"Mister Fantastic",
"option3":"Thing"
},
{
"question":"Who played the voice of the Lorax?",
"option1":"Danny DeVito",
"option2":"Mel Gibson",
"option3":"George Clooney"
},
{
"question":"What was the character's name Tom Hanks played in the Green Mile?",
"option1":"Paul Edgecomb",
"option2":"John Coffey",
"option3":"Percy Wetmore"
}
]
})
JS:
$(document).ready(function () {
var questionNumber=0;
var questionBank=new Array();
var stage="#game1";
var stage2=new Object;
var questionLock=false;
var numberOfQuestions;
var score=0;
function dataCallback(data) {
for(i=0;i<data.quizlist.length;i++){
questionBank[i]=new Array;
questionBank[i][0]=data.quizlist[i].question;
questionBank[i][1]=data.quizlist[i].option1;
questionBank[i][2]=data.quizlist[i].option2;
questionBank[i][3]=data.quizlist[i].option3;
}
numberOfQuestions=questionBank.length;
displayQuestion();
}//gtjson
function displayQuestion(){
var rnd=Math.random()*3;
rnd=Math.ceil(rnd);
var q1;
var q2;
var q3;
if(rnd==1){q1=questionBank[questionNumber][1];q2=questionBank[questionNumber][2];q3=questionBank[questionNumber][3];}
if(rnd==2){q2=questionBank[questionNumber][1];q3=questionBank[questionNumber][2];q1=questionBank[questionNumber][3];}
if(rnd==3){q3=questionBank[questionNumber][1];q1=questionBank[questionNumber][2];q2=questionBank[questionNumber][3];}
$(stage).append('<div class="questionText">'+questionBank[questionNumber][0]+'</div><div id="1" class="option">'+q1+'</div><div id="2" class="option">'+q2+'</div><div id="3" class="option">'+q3+'</div>');
$('.option').click(function(){
if(questionLock==false){questionLock=true;
//correct answer
if(this.id==rnd){
$(stage).append('<div class="feedback1">Correct</div>');
score++;
}
//wrong answer
if(this.id!=rnd){
$(stage).append('<div class="feedback2">Incorrect</div>');
}
setTimeout(function(){changeQuestion()},500);
}})
}//display question
function changeQuestion(){
questionNumber++;
if(stage=="#game1"){stage2="#game1";stage="#game2";}
else{stage2="#game2";stage="#game1";}
if(questionNumber<numberOfQuestions){displayQuestion();}else {displayFinalSlide();}
$(stage2).animate({"right": "+=800px"},"slow", function() {$(stage2).css('right','-800px');$(stage2).empty();});
$(stage).animate({"right": "+=800px"},"slow", function() {questionLock=false;});
}//change question
function displayFinalSlide(){
$(stage).append('<div class="questionText">You have finished the quiz!<br><br>Total questions: '+numberOfQuestions+'<br>Correct answers: '+score+'<br><br>Exit</div>');
}//display final slide
});//doc ready
So I found the solution by adjusting my JS as shown below by using the ajax function in jQuery. The solution located here, http://blogs.msdn.com/b/tconte/archive/2011/08/10/accessing-windows-azure-blob-storage-using-jquery.aspx led me down the right path. I hope this helps someone else.
$.ajax({
url: 'https://djmblob.blob.core.windows.net/quizzes/activity.json',
dataType: 'jsonp',
jsonpCallback: 'dataCallback',
success: function (data) {
for(i=0;i<data.quizlist.length;i++){
questionBank[i]=new Array;
questionBank[i][0]=data.quizlist[i].question;
questionBank[i][1]=data.quizlist[i].option1;
questionBank[i][2]=data.quizlist[i].option2;
questionBank[i][3]=data.quizlist[i].option3;
}
numberOfQuestions=questionBank.length;
displayQuestion();
}//gtjson
});

How can I fetch data in autosuggest textbox from server/database?

I have created an autosuggest textbox that is fetching data from defined array.How can I make it fetch data from server?
Following is my code-
HTML code-
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>autocomplete demo</title>
<link rel="stylesheet" href="jquery-ui.css">
<script src="jquery-1.10.2.js"></script>
<script src="jquery-ui.js"></script>
</head>
<body>
<label for="autocomplete">Select a programming language: </label>
<input id="autocomplete">
<script>
var tags = [ "c++", "java", "php", "coldfusion", "javascript", "asp", "ruby" ];
$( "#autocomplete" ).autocomplete({
source: function( request, response ) {
var matcher = new RegExp( "^" + $.ui.autocomplete.escapeRegex( request.term ), "i" );
response( $.grep( tags, function( item ){
return matcher.test( item );
}) );
}
});
</script>
</body>
</html>
Javascript files are of too much length.I can't paste them here.
There are number of ways in which you can populate an autocomplete box with data from your server. One of the easiest way to do so is, retrieve the data from your server and store it locally, and then use it.
var searchData = [];
$.get("ajax/mydata", function( data ) {
searchData.push(data);
});
And then, carry on with the autocomplete part.
$( "#autocomplete" ).autocomplete({
source: searchData,
...
});
Also, have a look at the jQuery UI Autocomplete documentation at http://jqueryui.com/autocomplete/
ps. Don't forget to mark this as the answer if it works for you.

Filter a list and requesting data via ajax

im new to javascript and phonegap and im sitting here the whole day and try to solve this problem.
I have a list and i want to filter some data. And before i filter it, i want to download some data from a server and add it to the list. ( the list is local and if someone uses the search function, new data should pop up too).
The idea is that i create the list with jquery and use the listviewbeforefilter-event to download the data from a server and add it to the list. Then jquery should filter the list.
It works fine when i search filter for 2 chars.
But this doesnt work as expected when i search for more than 2 chars.
I receive the correct data from the server and it will be added to my list but the there is no more filtering in my original list. So i see my original list + the loaded data.
Also the console.log("second") is shown first and then console.log("first). Somehow jquery/phonegap skips the .then part and then comes back to it.
I tried to put the 3 lines ($ul.html( content );$ul.listview( "refresh" );$ul.trigger( "updatelayout");) below the second console.log and then the filter of my local data works but the data from the server wont be shown.
I hope someone can help me with this weird problem.
Heres my code for the listviewbeforefilter-event:
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
<title>Listview Autocomplete - jQuery Mobile Demos</title>
<link rel="stylesheet" href="css/jquery.mobile-1.3.2.min.css" />
<script src="cordova.js"></script>
<script src="js/jquery-2.0.3.min.js"></script>
<script src="js/jquery.mobile-1.3.2.min.js"></script>
<script>
$( document ).on( "pageinit", "#myPage", function() {
$( "#autocomplete" ).on( "listviewbeforefilter", function ( e, data ) {
// this is a second list which is a backup. It is needed because after each search the original list is flooded with old entries.
var content = document.getElementById("autocomplete2").innerHTML;
var requestdata = "";
var $ul = $( this );
$input = $( data.input ),
value = $input.val();
// ajax call returns cities with at least 3 characters
if ( value && value.length > 2 ) {
$.ajax({
url: "http://gd.geobytes.com/AutoCompleteCity",
dataType: "jsonp",
crossDomain: true,
data: {
q: $input.val()
}
})
// The response is saved in html which i append to the original content
.then( function ( response ) {
var html = "";
console.log("first");
$.each( response, function ( i, val ) {
html += "<li>" + val + "</li>";
});
content = content + html;
$ul.html( content );
$ul.listview( "refresh" );
$ul.trigger( "updatelayout");
});
console.log("second");
}
});
});
</script>
and that is the body with the list:
</head>
<body>
<div data-role="page" id="myPage">
<div data-role="header" data-theme="f">
<h1>Listview </h1>
</div><!-- /header -->
<div data-role="content">
<div class="content-primary">
<ul id = "autocomplete" data-role="listview" data-filter="true" data-filter-placeholder="Search people..." data-filter-theme="d"data-theme="d" data-divider-theme="d">
<li data-role="list-divider">A</li>
<li>Adam Kinkaid</li>
<li>Alex Wickerham</li>
<li>Avery Johnson</li>
</ul>
</div><!--/content-primary -->
</div><!-- /content -->
<script type="text/javascript" charset="utf-8">
$(function(){
$( "#autocomplete2" ).hide();
});
</script>
<ul id = "autocomplete2" data-role="listview" data-filter-theme="d"data-theme="d" data-divider-theme="d">
<li data-role="list-divider">A</li>
<li>Adam Kinkaid</li>
<li>Alex Wickerham</li>
<li>Avery Johnson</li>
</ul>
</div><!-- /page -->
</body>
</html>
i fixed the issue. I changed the code :
content = content + html;
$ul.html( content );
to
$ul.append( html);
i made a custom filter and recognized that the .then was always called AFTER the filter began.
Thats really weird because this method listviewbeforefilter should do everything before the filtering begins. I guess its because the ajax takes so long and will be skipped but later coming back to the .then method when the response received. I thought maybe async:false would help, but nope.
So basically it filters my local data and hides the list which are not needed and than i append the received data to the list.

How can i pass values to a javascript array?

I am trying to implement the autocomplete method for textboxes.
I would like to use the example based on jquerys autocomplete provided here
<head>
<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" rel="stylesheet" type="text/css"/>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"></script>
<script>
$(document).ready(function() {
$("input#autocomplete").autocomplete({
source: ["c++", "java", "php", "coldfusion", "javascript", "asp", "ruby"]
});
});
</script>
</head>
The first and Main problem is that i do not know the way of passing my values to the source:
By saying that i mean, supposing i have a a server-side ASP.NET function
GetTheResults as listof(string) or
GetTheResults as string ()
how am i supposed to pass those values as source required by the auto-complete?
The second problem is that the specific way does not use AJAX.
Which means i guess on the load of the form i will load all the available values to the source. Isn't that an overkill?
What do you suggest instead?
Thanks and regards!
Oh, maybe I misunderstood - is GetTheResults a server-side ASP.NET function? You didn't say. This assumes it's a client-side JavaScript function. If it is server-side, why not implement the AJAX way?
If GetTheResults returns all values then I think you can just fill it in inline, i.e.
$("input#autocomplete").autocomplete({
source: GetTheResults()
}
});
The control will then filter the list for display. Or you can use the function source mechanism as documented on that page, e.g.
$("input#autocomplete").autocomplete({
source: function(request, response) {
var results = GetTheResultsForInput(request.term);
response(results);
}
});
You could instead manually write out the content from the server to the client. Try creating a public method called:
public string GetJs()
{
var data = this.GetTheResults();
string output = "[";
bool comma = false;
foreach (var i in data)
{
if (comma)
output += ", ";
else
comma = true;
output += '" + i + "'";
}
return output + "]";
}
And change your client-side script to look like:
$(document).ready(function() {
$("input#autocomplete").autocomplete({
source: <%= GetJs() %>
});
});
You may have to inject the <%= %> as a string, and instead do:
source: eval("<%= GetJs() %>")
Or you could write that entire JS from the page to the output.
HTH.

Categories

Resources