Jquery: delay 2 seconds before sending json request - javascript

Below is my script. It's a autosuggestion search script. The problem is that it penetrates the server with a huge amount of requests (it sends a request after each inserted character).
I need to change the script so that it waits 2 seconds after user has finished typing (and has inserted at least 3 characters) and only then sends request to the php file.
(function($){
$.fn.fsearch = function(){
var $searchInput = $(this);
$searchInput.after('<div id="divResult"></div>');
$resultDiv = $('#divResult');
$searchInput.focus();
$searchInput.addClass('searchi');
$resultDiv.html("<ul></ul><div id='search-footer' class='searchf'></div>");
$searchInput.keyup(function(e) {
var q=$(this).val();
if(q.length>2&&q.length<30){
var current_index = $('.selected').index(),
$options = $resultDiv.find('.option'),
items_total = $options.length;
$resultDiv.fadeIn();
$resultDiv.find('#search-footer').html("<img src='img/loader.gif' alt='Searching...'/>");
$.getJSON("/search.php",{searchword: q},function(jsonResult) {
var str='';
for(var i=0; i<jsonResult.length;i++)
{
str += '<li id=' + jsonResult[i].uid + ' class="option"><img class="profile_image" src="photos/'+jsonResult[i].media+'" alt="'+jsonResult[i].username+'"/><span class="name">' + jsonResult[i].username + '</span><br/>'+jsonResult[i].country+'</li>';
}
$resultDiv.find('ul').empty().prepend(str);
$resultDiv.find('div#search-footer').text(jsonResult.length + " results found...");
$resultDiv.find('ul li').first().addClass('selected');
});
$resultDiv.find('ul li').live('mouseover',function(e){
current_index = $resultDiv.find('ul li').index(this);
$options = $resultDiv.find('.option');
change_selection($options,current_index);
});
function change_selection($options,current_index){
$options.removeClass('selected');
$options.eq(current_index).addClass('selected');
}
} else{
$resultDiv.hide();
}
});
jQuery(document).live("click", function(e) {
var $clicked = $(e.target);
if ($clicked.hasClass("searchi") || $clicked.hasClass("searchf")){
}
else{
$resultDiv.fadeOut();
}
});
$searchInput.click(function(){
var q=$(this).val();
if(q.length>2&&q.length<30) {
$resultDiv.fadeIn();
}
});
$resultDiv.find('li').live("click",function(e){
var id = $(this).attr('id');
var name = ($(this).find('.name').text());
$searchInput.val(name);
});
};
})(jQuery);
After reading this question I added the following solution to my script:
var timer;
var x;
$(".some-input").keyup(function () {
if (x) { x.abort() } // If there is an existing XHR, abort it.
clearTimeout(timer); // Clear the timer so we don't end up with dupes.
timer = setTimeout(function() { // assign timer a new timeout
x = $.getJSON(...); // run ajax request and store in x variable (so we can cancel)
}, 2000); // 2000ms delay, tweak for faster/slower
});
unfortunately, it does not work:
TypeError: e.nodeName is undefined jquery-1.11.0.min.js:4:9004

Related

How to get JS variable value on one page passed back to another page in PHP

I currently have two pages coded in php one page is called upload.php and the other page is called processing.php.
in the processing.php I currently have some Javascript that is ran it’s purpose is to check a log file for a video encoding progress to get the percentage left. this variable is called “progress” (This works fine when using console.log on the processing.php and I can see the incrementing percentage) I need to be able to get this value back to my upload.php page so that I can dynamically update a progress bar with its current value.
I already have one part of the puzzle working and that's to show a progress bar of the file uploading.
I have included some of the JS code on my upload.php and the JS code using in the processing.php page.
One thing that I tried was to have the JS variable inserted into a PHP session variable on the processing.php page, then echo this session variable out on the upload.php.
I have included in my code snippets below my attempt at using sessions.
Upload.php
<?php session_start();?>
<?php
$formProvider = new VideoDetailsFormProvider($con);
echo $formProvider->createUploadForm();
?>
</div>
<script>
$("form").submit(function() {
$("#loadingModal").modal("show");
var $el = $("#loadingModal");
$form = $(this);
uploadVideo($form, $el);
});
function uploadVideo($form, $el){
var formdata = new FormData($form[0]); //formelement
var ajax= new XMLHttpRequest();
ajax.upload.addEventListener("progress", function(event){
var percent = Math.round(event.loaded /event.total) * 100;
$el.find('#progressBarUpload').width(percent+'%').html(percent+'%');
//console.log(percent);
});
//progress completed load event
ajax.addEventListener("load", function(event){
$el.find('#progressBarUpload').addClass('progress-bar bg-success').html('Upload completed...');
});
ajax.addEventListener("error", function(event){
$el.find('#status').innerhtml = "Upload Failed";
});
ajax.addEventListener("abort", function(event){
$el.find('#status').innerhtml = "Upload Aborted";
});
ajax.open("POST", "processing.php");
ajax.send(formdata);
}
Please wait. This might take a while.
<?php echo($_SESSION['convertProgress']);?>
<div class="progress">
<div id="progressBarUpload" class="progress-bar" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>
Processing.php
<?php session_start();
$convertProgressTest = $_SESSION['convertProgress'];
?>
<script>
var _progress = function(i){
i++;
// THIS MUST BE THE PATH OF THE .txt FILE SPECIFIED IN [1] :
var logfile = 'uploads/videos/logs/output.txt';
/* (example requires dojo) */
$.post(logfile).then( function(content){
// AJAX success
var duration = 0, time = 0, progress = 0;
var resArr = [];
// get duration of source
var matches = (content) ? content.match(/Duration: (.*?), start:/) : [];
if( matches.length>0 ){
var rawDuration = matches[1];
// convert rawDuration from 00:00:00.00 to seconds.
var ar = rawDuration.split(":").reverse();
duration = parseFloat(ar[0]);
if (ar[1]) duration += parseInt(ar[1]) * 60;
if (ar[2]) duration += parseInt(ar[2]) * 60 * 60;
// get the time
matches = content.match(/time=(.*?) bitrate/g);
console.log( matches );
if( matches.length>0 ){
var rawTime = matches.pop();
// needed if there is more than one match
if ($.isArray(rawTime)){
rawTime = rawTime.pop().replace('time=','').replace(' bitrate','');
} else {
rawTime = rawTime.replace('time=','').replace(' bitrate','');
}
// convert rawTime from 00:00:00.00 to seconds.
ar = rawTime.split(":").reverse();
time = parseFloat(ar[0]);
if (ar[1]) time += parseInt(ar[1]) * 60;
if (ar[2]) time += parseInt(ar[2]) * 60 * 60;
//calculate the progress
progress = Math.round((time/duration) * 100);
}
resArr['status'] = 200;
resArr['duration'] = duration;
resArr['current'] = time;
resArr['progress'] = progress;
console.log(resArr);
/* UPDATE YOUR PROGRESSBAR HERE with above values ... */
/* $("#progressBarconvert").width(progress+'%').html(progress+'%');
if(progress==100){
$("#progressBarconvert").addClass('progress-bar bg-success').html('Conversion Completed...');
}*/
var convertProgress = progress;
if(progress==0 && i>20){
//TODO err - giving up after 8 sec. no progress - handle progress errors here
console.log('{"status":-400, "error":"there is no progress while we tried to encode the video" }');
return;
} else if(progress<100){
setTimeout(function(){ _progress(i); }, 400);
}
} else if( content.indexOf('Permission denied') > -1) {
// TODO - err - ffmpeg is not executable ...
console.log('{"status":-400, "error":"ffmpeg : Permission denied, either for ffmpeg or upload location ..." }');
}
},
function(err){
// AJAX error
if(i<20){
// retry
setTimeout(function(){ _progress(0); }, 400);
} else {
console.log('{"status":-400, "error":"there is no progress while we tried to encode the video" }');
console.log( err );
}
return;
});
}
setTimeout(function(){ _progress(0); }, 800);
</script>
Since you dont want to leave upload.php you have to add return false; right after uploadVideo($form, $el);
Otherwise you trigger the upload asynchronously and go to progress.php synchronously(which means you leave upload.php)
You have 3 responsibilities here, so you could do it with 3 files:
upload.php - display the upload form
convert.php - do the conversion
progress.php - get the progress
In your convert.php you will need to add the line $_SESSION['convertProgress'] = convertProgress;
In your upload.php you can update your progressbar now by:
$.ajax('progress.php', function(content) {
// set element value etc...
});
As soon as you start the upload the File gets uploaded and converted by convert.php asynchronously. You can now trigger a JS-Timer, which does the above call to progress.php over and over until it reaches 100.
If you want to be able to do some errorhandling you can use JSON to pass more data back to your upload.php which calls progress.php.
PHP (example):
json_encode([
'progress' => 0,
'message' => '',
]);
JS decode:
JSON.parse(<content of progress.php>)
I have managed to resolve this now it's not pretty and it may not be the best way but it works for me, using #Pilan advice and help this is my workaround.
have 3 pages
The Update.php Page, The Processing.php Page and convertProgress.php, the convertProgress.php Page contains the the Javascript code mentioned at the beginning of my post. The upload.php contains the following.
var testing;
function beginUpload() {
$.ajax({
url: 'convertProgress.php',
type: 'POST',
//async: false,
data: {},
success: function (response) { //we got the response
if(response.progress){
testing = response.progress
console.log(testing);
}else {
beginUpload();
getProgress();
}
//var testing = response.progress;
},
error: function (jqxhr, status, exception) {
alert('Exception:', exception);
}
});
//console.log(testing);
}
Upload.php also has the same javascript code as the convertProgress.php
<script>
function getProgress() {
var _progress = function (i) {
i++;
// THIS MUST BE THE PATH OF THE .txt FILE SPECIFIED IN [1] :
var logfile = 'uploads/videos/logs/output.txt';
/* (example requires dojo) */
$.post(logfile).then(function (content) {
// AJAX success
var duration = 0, time = 0, progress = 0;
var resArr = [];
// get duration of source
var matches = (content) ? content.match(/Duration: (.*?), start:/) : [];
if (matches.length > 0) {
var rawDuration = matches[1];
// convert rawDuration from 00:00:00.00 to seconds.
var ar = rawDuration.split(":").reverse();
duration = parseFloat(ar[0]);
if (ar[1]) duration += parseInt(ar[1]) * 60;
if (ar[2]) duration += parseInt(ar[2]) * 60 * 60;
// get the time
matches = content.match(/time=(.*?) bitrate/g);
console.log(matches);
if (matches.length > 0) {
var rawTime = matches.pop();
// needed if there is more than one match
if ($.isArray(rawTime)) {
rawTime = rawTime.pop().replace('time=', '').replace(' bitrate', '');
} else {
rawTime = rawTime.replace('time=', '').replace(' bitrate', '');
}
// convert rawTime from 00:00:00.00 to seconds.
ar = rawTime.split(":").reverse();
time = parseFloat(ar[0]);
if (ar[1]) time += parseInt(ar[1]) * 60;
if (ar[2]) time += parseInt(ar[2]) * 60 * 60;
//calculate the progress
progress = Math.round((time / duration) * 100);
}
resArr['status'] = 200;
resArr['duration'] = duration;
resArr['current'] = time;
resArr['progress'] = progress;
console.log(resArr);
/* UPDATE YOUR PROGRESSBAR HERE with above values ... */
$("#progressBarconvert").width(progress+'%').html(progress+'%');
if(progress==100){
$("#progressBarconvert").addClass('progress-bar bg-success').html('Conversion Completed...');
}
if (progress == 0 && i > 20) {
//TODO err - giving up after 8 sec. no progress - handle progress errors here
console.log('{"status":-400, "error":"there is no progress while we tried to encode the video" }');
return;
} else if (progress < 100) {
setTimeout(function () {
_progress(i);
}, 400);
}
} else if (content.indexOf('Permission denied') > -1) {
// TODO - err - ffmpeg is not executable ...
console.log('{"status":-400, "error":"ffmpeg : Permission denied, either for ffmpeg or upload location ..." }');
}
},
function (err) {
// AJAX error
if (i < 20) {
// retry
setTimeout(function () {
_progress(0);
}, 400);
} else {
console.log('{"status":-400, "error":"there is no progress while we tried to encode the video" }');
console.log(err);
}
return;
});
}
setTimeout(function () {
_progress(0);
}, 800);
}
</script>
It's not pretty but it works for me. I hope this helps anyone that would like to get the conversion Progress from FFMPEG and populate a bootstrap Progress bar

Phantomjs update values of var?

I have the below phantomjs program where the website contains a drop down list ddlLevel3
var page = require('webpage').create();
page.onConsoleMessage = function(str) {
console.log(str);
}
var z=0;
var z_l=0;
var op1='#ddlDivision'
var op2='#ddlLevel1'
var op3='#ddlLevel2'
var op4='#ddlLevel3'
function selectOption(selector, optionIndex) {
page.evaluate(function(selector, optionIndex){
var op4='#ddlLevel3'
var sel = document.querySelector(selector);
var sel4 = document.querySelector(op4);
sel.selectedIndex = optionIndex;
var event = document.createEvent("UIEvents"); // See update below
event.initUIEvent("change", true, false);
sel.dispatchEvent(event);
this.dispatchEvent(event);
z_l=sel4.length;
console.log("len: "sel4.length+" "+z_l);
}, selector, optionIndex);
}
page.open(...{
function loop4 () {
selectOption(op4,z);
window.setTimeout(function () {
go();
z++;
if (z < z_l) {
loop4();
}
}, 3000);
}
loop4();
});
I am trying to run loop4(). But the value of z_l is not changing from '0'.
In line console.log("len: "sel4.length+" "+z_l); Here values is proper.
But its not reflected back in loop4() in if (z < z_l), and remains 0 always.
What am I doing wrong?
I I wanted to get the value of z_l updated.I just need to use page.evaluate and assign it to z_l as below. Just made these changes in loop4().
function loop4 () {
var z_l = page.evaluate(function() {
var op4='#ddlLevel3'
return document.querySelector(op4)
});
selectOption(op4,z);
.
.
.
}

Javascript Performance Testing, identical tests at different speeds

I've got some code for testing performance of jQuery selectors. I run the tests 3 times with 100000 repetitions in a browser console. The first test is always the slowest, then, the following two are nearly equal in speed. Has anybody an idea why?
Here's the fiddle: http://jsfiddle.net/05xq70na/, the execution times are logged in browser console.
var repetitions = 100000;
var html = '<ul><li id="parent"><div id="child" class="child" value="test"></div></li></ul>';
var time = [];
var finished = false;
var tests = {
"SelectorById": function(){
var element;
element = $("#child");
},
"SelectorByClass": function(){
var element;
element = $(".child");
},
"SelectorByTag": function(){
var element;
element = $("li");
}
}
function showResults(loopCounter) {
if(!finished) {
finished = true;
console.log("\nResults (" + loopCounter + " repetitions):");
for(executionTime in time) {
console.log(executionTime + ": " + (time[executionTime] / loopCounter) + " ms");
}
}
}
function perform(test, string) {
var startTime,
endTime,
nextTest = tests[test];
if(time[test + string] === undefined) {
time[test + string] = 0;
}
startTime = performance.now();
nextTest();
endTime = performance.now();
time[test + string] += (endTime - startTime);
}
function benchmark(tests) {
for(var i=0, loopCounter=1; i<repetitions; i++) {
// console.log('repetition ' + loopCounter);
for(test in tests) {
// console.log('\texecute ' + test);
perform(test, "1");
perform(test, "2");
perform(test, "3");
}
loopCounter++;
if(loopCounter>repetitions) {
showResults(--loopCounter);
};
}
}
document.getElementsByTagName('body')[0].innerHTML = html;
benchmark(tests);
I have tested the simple jQuery selector in JSLitmus (JSFiddle).
JSLitmus.test('jQuery ID selector 1', function(counter) {
while(counter--) {
$('#test');
}
});
...
The result is like:
The performance of ID selectors vary every time, but there is no fixed pattern.
I update your code to run every tests for 7 times: JSFiddle. Then the first run also spends most time, however the rest spend some time comparable. Since JSLitmus performs something called calibration, I am afraid your testing code is not so fare, especially when there are so many function calls.

JS mini-game in grid, browser frozen after first replication

I'm trying to create a small game that replicate neighbors cells in a grid. I use a web worker that draw replicate cells every seconds. I'm able to replicate the first second. If my initial cell is row3col3, the new replicated cells will be :
row3col2, row3col4
row2col3, row4col3
The problem is, after the first second (and the replication), the game freezes, and i'm not able to do something. Can't click on cells, etc.
EDIT : After few seconds, it go to '00:02' but Chrome crashed "Aw, Snap! Something went wrong...' [RELOAD]
EDIT 2 : After looking on the memory used, It appears I have an memory overflow, 16000 Mb ! My method is bad, so.
I know my code is not really optimised, and I think that is the problem. Unfortunatly, i'm not able to do more efficient code, so I ask some help to you guys, to give me some ways to explore.
Here the code :
var lastClicked;
var cellTab = Array();
var replicant = Array();
var newReplicant = Array();
var count = 5;
var rows = 20;
var cols = 20;
var randomRow = Math.floor((Math.random() * rows));
var randomCol = Math.floor((Math.random() * cols));
var grid = clickableGrid(rows, cols,randomRow,randomCol,cellTab, function(el,row,col,i){
console.log("You clicked on element:",el);
console.log("You clicked on row:",row);
console.log("You clicked on col:",col);
console.log("You clicked on item #:",i);
$(el).addClass('clicked');
lastClicked = el;
});
document.getElementById("game").appendChild(grid);
function clickableGrid( rows, cols, randomRow, randomCol, cellTab, callback ){
var i=0;
var grid = document.createElement('table');
grid.className = 'grid';
for (var r=0;r<rows;++r){
var tr = grid.appendChild(document.createElement('tr'));
for (var c=0;c<cols;++c){
var cell = tr.appendChild(document.createElement('td'));
$(cell).addClass('row'+r+'col'+c);
if(randomCol == c && randomRow == r)
{
storeCoordinate(r, c, replicant);
$(cell).css('background', '#000000');
}
storeCoordinate(r, c, cellTab);
cell.addEventListener('click',(function(el,r,c,i){
return function(){
callback(el,r,c,i);
}
})(cell,r,c,i),false);
}
}
return grid;
}
function storeCoordinate(xVal, yVal, array)
{
array.push({x: xVal, y: yVal});
}
function replicate(replicant)
{
for (var i = 0; i < replicant.length; i++) {
console.log(replicant);
var supRowX = replicant[i].x-1;
var supRowY = replicant[i].y;
storeCoordinate(supRowX, supRowY, newReplicant);
var subRowX = replicant[i].x+1;
var subRowY = replicant[i].y;
storeCoordinate(subRowX, subRowY, newReplicant);
var supColsX = replicant[i].x;
var supColsY = replicant[i].y-1;
storeCoordinate(supColsX, supColsY, newReplicant);
var subColsX = replicant[i].x;
var subColsY = replicant[i].y+1;
storeCoordinate(subColsX, subColsY, newReplicant);
}
}
function drawReplicant(replicant, cellTab)
{
for (var i = 0; i < replicant.length; i++) {
if($.inArray(replicant[i], cellTab))
{
$('.row'+replicant[i].x+'col'+replicant[i].y).css('background', '#000000');
}
}
}
var w = null; // initialize variable
// function to start the timer
function startTimer()
{
// First check whether Web Workers are supported
if (typeof(Worker)!=="undefined"){
// Check whether Web Worker has been created. If not, create a new Web Worker based on the Javascript file simple-timer.js
if (w==null){
w = new Worker("w.countdown.js");
}
// Update timer div with output from Web Worker
w.onmessage = function (event) {
document.getElementById("timer").innerHTML = event.data;
console.log(event.data);
replicate(replicant);
replicant = newReplicant;
drawReplicant(replicant, cellTab);
};
} else {
// Web workers are not supported by your browser
document.getElementById("timer").innerHTML = "Sorry, your browser does not support Web Workers ...";
}
}
// function to stop the timer
function stopTimer()
{
w.terminate();
timerStart = true;
w = null;
}
startTimer();
And here, the web worker :
var timerStart = true;
function myTimer(d0)
{
// get current time
var d=(new Date()).valueOf();
// calculate time difference between now and initial time
var diff = d-d0;
// calculate number of minutes
var minutes = Math.floor(diff/1000/60);
// calculate number of seconds
var seconds = Math.floor(diff/1000)-minutes*60;
var myVar = null;
// if number of minutes less than 10, add a leading "0"
minutes = minutes.toString();
if (minutes.length == 1){
minutes = "0"+minutes;
}
// if number of seconds less than 10, add a leading "0"
seconds = seconds.toString();
if (seconds.length == 1){
seconds = "0"+seconds;
}
// return output to Web Worker
postMessage(minutes+":"+seconds);
}
if (timerStart){
// get current time
var d0=(new Date()).valueOf();
// repeat myTimer(d0) every 100 ms
myVar=setInterval(function(){myTimer(d0)},1000);
// timer should not start anymore since it has been started
timerStart = false;
}
Maybe it's because I use jQuery ?

Using each() method to animate typing of code

I am trying to use JQuery's each() method to animate typing on multiple blocks of code, but I keep getting this error:
Uncaught TypeError: Cannot call method 'createDocumentFragment' of undefined
Check out some example code in this Fiddle...
And for your convenience, the JS is listed below:
$('.typeanimator').each(function(index) {
console.log(index);
var codeBlock = $(this).text();
var done;
var blockLength = codeBlock.length;
var charCounter = 0;
$(this).text('|');
(function typeAnimator() {
var typingSimulator = Math.round(Math.random() * (200));
done = setTimeout(function() {
console.log("Le print.");
charCounter++;
var typeSection = codeBlock.substring(0, charCounter);
$(this).text(typeSection + '|');
typeAnimator();
if (charCounter == blockLength) {
$(this).text($(this).text().slice(0, -1));
clearTimeout(done);
}
}, typingSimulator);
}());
});
The problem is in the use of $(this) inside the typeAnimator function. You are actually want to refer the this from the parent function but instead you are getting a totally different this. So, use a temporary variable to store the $(this)
$('.typeanimator').each(function(index) {
...
var self = $(this);
self.text('|');
(function typeAnimator() {
var typingSimulator = Math.round(Math.random() * (200));
done = setTimeout(function() {
...
self.text(typeSection + '|');
typeAnimator();
if (charCounter == blockLength) {
self.text(self.text().slice(0, -1));
clearTimeout(done);
}
}, typingSimulator);
}());
});
Updated fiddle
$('.typeanimator').each(function(index, current) {
console.log(index);
var codeBlock = $(current).text();
var done;
var blockLength = codeBlock.length;
var charCounter = 0;
$(current).text('|');
(function typeAnimator(context) {
var typingSimulator = Math.round(Math.random() * (200));
done = setTimeout(function() {
console.log("Le print.");
charCounter++;
var typeSection = codeBlock.substring(0, charCounter);
$(context).text(typeSection + '|');
typeAnimator(context);
if (charCounter == blockLength) {
$(context).text($(context).text().slice(0, -1));
clearTimeout(done);
}
}, typingSimulator);
}(current));
});
This should work, always remember that javascript is really picky about the context when using 'this'. As well .each() has nifty parameter of current item :) Gl, and good code.

Categories

Resources