jQuery.post dynamic data callback function - javascript

I have a script that requires quite a few seconds of processing, up to about minute. The script resizes an array of images, sharpens them and finally zips them up for the user to download.
Now I need some sort of progress messages.
I was thinking that with jQuery's .post() method the data from the callback function would progressively update, but that doesn't seem to work.
In my example I am just using a loop to simulate my script:
$(document).ready(function() {
$('a.loop').click(function() {
$.post('loop.php', {foo:"bar"},
function(data) {
$("div").html(data);
});
return false;
});
});
loop.php:
for ($i = 0; $i <= 100; $i++) {
echo $i . "<br />";
}
echo "done";

Update: Getting progress information is a lot easier since jQuery Ajax requests have a promise interface. Use this answer:
https://stackoverflow.com/a/32272660/18771
The original answer below is outdated (it is originally from 2010). It still works but is more complicated than it needs to be. I'll keep it in place for reference and and comparison.
You need some kind of progress info from the server. The ajax callbacks do no progressive work, they fire just once - after the request returned successfully.
So... in PHP you would need something like this:
/* progress.php */
$batch_done = some_way_to_find_out_that_number();
$batch_size = some_way_to_find_out_that_number_too();
header('Content-type: application/json');
// TODO: format number
echo '{"progress":'. ($batch_size==0 ? '0' : $batch_done*100.0/$batch_size).'}';
For this to work your image processing script must leave some evidence of its progress of course.
And in JavaScript something like this:
$(document).ready(function() {
$('a.loop').click(function() {
var queryData = {foo:"bar"};
// prepare a function that does cyclic progress checking
var progressCheck = function() {
$.getJSON(
"progress.php", queryData,
function(data) {
$("div.progress").css("width", data.progress+"%");
}
)
};
$.post(
'loop.php', queryData,
/* create the post request callback now */
function(intvalId){
return function(data) {
$("div").html(data);
clearInterval(intvalId);
}
}( setInterval(progressCheck, 1000) )
);
return false;
});
});
This part requires some explanation:
function(intvalId){
return function(data) {
$("div").html(data);
clearInterval(intvalId);
};
}( setInterval(progressCheck, 1000) )
function(intvalId) is an anonymous function that takes one argument - an interval ID. This ID is necessary to stop an interval that has been set up via setInterval(). Luckily, the call to setInterval() returns this very ID.
The anonymous outer function returns an inner function(data), this one will be the actual callback for $.post().
We call the outer function immediately, doing two things in the process: Triggering off the interval with setInterval() and passing in its return value (the ID) as an argument. This argument value will be available to the inner function at its call time (which may be some minutes in the future). The callback for post() now can actually stop the interval.
As an exercise for you ;)
Modify the ajax call such that it stops the interval on request error or timeout, too. Currently, if the callback is never run (and it runs on success only!), the interval will never stop.
Make sure the post() cannot be triggered twice inadvertently.

Thanks to Tomalak I finally put something together that works.
Since I am not actually writing my image files on the server when processing the batch I wrote a log file that I am consulting in the progress.php script.
I would like to know if this is the best way of doing this. I wanted to avoid writing to a file and tried with PHP's $_session but cannot seem to progressively read from it.
Is this possible with $_session?
HTML:
<a class="download" href="#">request download</a>
<p class="message"></p>
JS:
$('a.download').click(function() {
var queryData = {images : ["001.jpg", "002.jpg", "003.jpg"]};
var progressCheck = function() {
$.get("progress.php",
function(data) {
$("p.message").html(data);
}
);
};
$.post('proccess.php', queryData,
function(intvalId) {
return function(data) {
$("p.message").html(data);
clearInterval(intvalId);
}
} (setInterval(progressCheck, 1000))
);
return false;
});
process.php:
$arr = $_POST['images'];
$arr_cnt = count($arr);
$filename = "log.txt";
$i = 1;
foreach ($arr as $val) {
$content = "processing $val ($i/$arr_cnt)";
$handle = fopen($filename, 'w');
fwrite($handle, $content);
fclose($handle);
$i++;
sleep(3); // to mimic image processing
}
echo "<a href='#'>download zip</a>";
progress.php:
$filename = "log.txt";
$handle = fopen($filename, "r");
$contents = fread($handle, filesize($filename));
fclose($handle);
echo $contents;

Related

How properly proccess jQuery AJAX in WordPress plugin

I'm trying to add ajax autosave to my settings page in plugin and made this code:
<?php
function cfgeo_settings_javascript() { ?>
<script type="text/javascript" >
(function($){
$(document).ready(function(){
$("input[id^='cf_geo_'], select[id^='cf_geo_'], textarea[id^='cf_geo_']").on("change keyup", function(){
var This = $(this),
name = This.attr("name"),
value = This.val(),
data = {};
data['action'] = 'cfgeo_settings';
data[name] = value;
console.log(data);
console.log(ajaxurl);
$.post(ajaxurl, data).done(function(returns){
console.log(returns);
});
});
});
}(window.jQuery));
</script> <?php
}
add_action( 'admin_footer', 'cfgeo_settings_javascript');
function cfgeo_settings_callback() {
global $wpdb; // this is how you get access to the database
var_dump($_POST);
if (isset($_POST)) {
// Do the saving
$front_page_elements = array();
$updates=array();
foreach($_POST as $key=>$val){
if($key != 'cfgeo_settings')
update_option($key, esc_attr($val));
}
echo 'true';
}
else
echo 'false';
wp_die(); // this is required to terminate immediately and return a proper response
}
add_action( 'wp_ajax_cfgeo_settings', 'cfgeo_settings_callback');
?>
I find problem that everytime I want to send this simple ajax request I get 0 what is realy enoying.
Here is Console Log when I try to made some change in select option box:
Object {action: "cfgeo_settings", cf_geo_enable_ssl: "true"}
admin.php?page=cf-geoplugin-settings:1733 /wp-admin/admin-ajax.php
admin.php?page=cf-geoplugin-settings:1736 0
What's wrong in my ajax call or PHP script?
I need to mention that both codes are in the one PHP file.
You should have to follow guideline of WordPress ajax method by this admin ajax reference. Please follow this.
https://codex.wordpress.org/AJAX_in_Plugins
Here is a working example with notes included in the comments, there are a lot of don't does in your code and this example addresses those concerns in the code comments.
https://gist.github.com/topdown/23070e48bfed00640bd190edaf6662dc

Ajax/Jquery - Call javascript function upon data being returned from server/ Parallel SQL query execution using ajax

I have a PHP array of values. I loop through it, make ajax calls to the server by iterating through a for loop (I totally understand that making ajax cals in a for loop is not a great idea. Any suggestions/pointers to doing this a bette way would be awesome no doubt. I'd like to seek an answer to this question however please.). The data from the server takes different times based on what is to be processed & returned.
The problem I have is the showCustomerUsageChart function call doesn't get invoked at all at any stage. I tried debugging this by setting a breakpoint on this function's entry & see that there is no call made to it at all. However, I can see that the JSON data is being returned by the server at different points in time upon the respective data being available. I understand I've implemented this incorrectly, no doubt.
AJAX world is not all too familiar to me. I have looked up quite a few questions in this forum, but, kind of struggling to put the pieces together.
Could I request help to achieve what I'm after please. I'd be highly grateful to any help.
<script>
var ajaxurl = 'myDbHandler.php';
<?php for ($k = 0; $k < count($propertyCustomer); $k++) { ?>
data = {
'param1': paramFromUser1,
'param2': paramFromUser2,
'param3': paramFromUser3,
'lookUpParamId': "<?php echo $k ?>"
};
$.post(ajaxurl, data,function (response) {
var resp = $.parseJSON(response);
showCustomerUsageChart(
"<?php echo $propertyCustomer[$k][0] ?>",
"<?php echo $propertyCustomer[$k][1] ?>",
"<?php echo $propertyCustomer[$k][2] ?>",
"<?php echo $propertyCustomer[$k][3] ?>",
resp,
);
});
<?php } ?>
</script>
So here's one way to go about it instead, I avoided using php in javascript so the code and markup are cleaner.
To simulate the lag coming from your queries I did this:
myDbHandler.php:
$number = rand(2, 11);
sleep($number);
echo 'success after ' . $number . ' seconds';
The original .php file now looks like this (test.php):
<?php
// Array filled with testdata:
$propertyCustomer = array(
array('value1', 'value2', 'value3', 'value4'),
array('value1', 'value2', 'value3', 'value4'),
array('value1', 'value2', 'value3', 'value4')
);
// Make a string that html can handle and also encode the array above to a jsonString:
$json = htmlentities(json_encode($propertyCustomer));
?>
<!-- Echo the string as data-attribute -->
<div id="holdingElement" data-array="<?php echo $json ?>"></div>
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script src="test.js"></script>
I seperated js from markup, because I can't stand ugly code (test.js):
$(document).ready(function () {
// Get the array from the element:
var phpArray = $('#holdingElement').data('array');
// Console.log for testing:
console.log(phpArray);
// Loop through the array with the jQuery each function:
$.each(phpArray, function(k, phpArrayValue){
// The makeCall function returns a ajaxObject so the object gets put in var promise
var promise = makeCall(k);
// Now fill the success function in this ajaxObject (could also use .error() or .done() )
promise.success(function(response){
// When success, call the function and use the values out of the array above
showCustomerUsageChart(
phpArrayValue[0],
phpArrayValue[1],
phpArrayValue[2],
phpArrayValue[3],
response
);
});
});
});
function makeCall(paramId) {
// Just testdata:
var paramFromUser1 = 'val1';
var paramFromUser2 = 'val2';
var paramFromUser3 = 'val3';
// Use ajax instead of $.post to use the success function, and return this ajaxObject
return $.ajax({
url: 'myDbHandler.php',
type: 'post',
data: {
'param1': paramFromUser1,
'param2': paramFromUser2,
'param3': paramFromUser3,
'lookUpParamId': paramId
}
});
}
// Function to log the results from the ajax call:
function showCustomerUsageChart(val1, val2, val3, val4, response) {
console.log(val1, val2, val3, val4, response);
}
I hope this makes any sence, and that it works for you!
Your code is faulty there:
showCustomerUsageChart(
<?php echo $propertyCustomer[$k][0] ?>
You have to put a "," after the PHP closing tag.

Array json between ajax and php

I'm developing a simple guestbook and I want to update the table with all messages without refreshing the page because if someone it's writing a comment and the page refreshes the comment will be lost.
So I began writing some code with ajax to update the table but I don't know how to send an array (with comment, username, date ecc) from php to ajax.
In the database I have a column named "wrote" and it can be 0 (unread) or 1 (read). 1 it's when the messages it's already on the table.
This is what I've done since now, maybe it's wrong
getGuest.php
<?php
include("Database.php");
$Database = new Database( "localhost", "root", "1234");
$Database->connectToServer();
$Database->connectToDatabase("test");
$result = $Database->unreadMessages();
$rows=mysql_fetch_array($result);
echo json_encode($rows);
?>
Script.js
window.onload = function(){
interval = window.setInterval('updateGuest()',5000);
}
function updateGuest() {
$.ajax({
url: 'getGuest.php',
method: 'get',
success: on_getGuest_success,
error: on_error
});
}
function on_getGuest_success(data) {
for(var i=0; i<data.length;i++) {
// HERE I WANT TO ADD A ROW WITH ALL MESSAGE UNREAD BUT I DONT KNOW WHAT I HAVE TO DO
}
}
function on_error() {
//do something
}
Make sure the JSON contains an array
Add headers
use getJSON
Like this:
PHP
$data = array();
while ($row = mysql_fetch_assoc($result)) {
$data[] = $row;
}
header("content-type: application/json");
echo json_encode($data);
JS:
$(function() { // when page has loaded
var tId = setInterval(function() { // save the tId to allow to clearTimeout if needed
$.getJSON("getGuest.php",function(data) { // call the server using jQuery's JSON access
$('.guestbook').empty(); // empty the container
var rows = []; // create an array to hold the rows
$.each(data,function(_,item) { // loop over the returned data adding rows to array
rows.push('<tr><td class="name" width="10%">' + item.name + '</td></tr>');
});
$('.guestbook').html(rows.join()); // insert the array as a string
});
},5000); // every 5 secs
});
I would personally only return what was new since last time

How has the return of a PHP-function to look like to be valid for use by AJAX and PHP?

I got an input field. The user-input is getting checked on the fly by some AJAX request. The user is then getting informed whether his/her input is ok or not.
After submitting, the input has to be checked again for the same characteristics as it was checked before by AJAX(in case of JavaScript is deactivated).
AJAX uses "check.php" asynchronously.
<?php
include 'foo.php';
$input= $_POST['input'];
checkSomethingElse(testSomething($input));
?>
Then i got a "submit.php" file that is getting called on submission. It checks the input, and then writes the input into Database.
<?php
include 'foo.php';
$input= $_POST['input'];
checkSomethingElse(testSomething($input));
foo(){
//write input into Database}
?>
The "foo.php" looks like this
<?php
function testSomething(){
//do something
}
function checkSomethingElse(){
//test...
echo value // e.g. echo "true"
return value // e.g. return true
?>
(e.g. validate and sanitize input and other checks)
For the purpose of AJAX/JS/JQuery to use the returned value, it is returned trough "echo".
For the purpose of PHP to use the returned value, it is returned trough "return".
In case of AJAX-request there is everything fine, since it ignores the "return" and uses only "echo". In case of PHP it uses the "return value" and prints out the "echo value".
So the question is:
Is this structure logically and functionally ok? And how can i fix this code to spit out a string trough the "echo", when the user is not using JavaScript?
Thank You.
first of all the first issue i can see is that you are calling echo after return ... which will never happen, because execution of the function ceases once it hits return.
I would suggest just making your functions that return a value and then determine if you need to echo it afterwards ...
<?php
function some_function() {
return "value";
}
$value = some_function();
if (isset($_POST["returnajax"])) {
echo $value;
}
?>
as #rm-vanda suggests - json_encode may be useful to you if you are processing the AJAX request expecting a JSON. In this case it might look something like this...
function some_function() {
return "value";
}
function some_other_function() {
return "another_value";
}
$values = array();
$values[] = some_function();
$values[] = some_other_function();
if (isset($_POST["returnajax"])) {
header("Content-Type: application/json");
echo json_encode($values);
}
the resulting echo would look something like this:
["value","another_value"]
unfortunately, you may find that jquery will not like non well formed json. what i usually do is the following:
if (isset($_POST["returnajax"])) {
header("Content-Type: application/json");
echo json_encode(array("values"=>$values));
}
which would result in:
{"values":["value","another_value"]}
Separate the display logic from the validation logic.
For example:
// validation functions
function testSomthing(){
//test...
return $value; // e.g. return true
}
function checkSomethingElse(){
//test...
return $value; // e.g. return true
}
// calling logic in check.php
include 'foo.php';
$result = false;
if (!empty($_POST['input']) {
$input= $_POST['input'];
$result = checkSomethingElse(testSomething($input));
}
$return = new stdClass();
$return->result = $result;
header("Content-Type: application/json");
echo json_encode($return);
Note: it is not clear from your example why you have nested validation function calls (i.e. checkSomethingElse(testSomething($input))). I don't think it will work that way (because you will pass true/false result to outer function call), but I am showing the code here the same as you do, as I certainly don't have full picture as to function usage to offer up an alternative.
You can check the variable $_SERVER['HTTP_X_REQUESTED_WITH']
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
/* special ajax here echo for example*/
}
else {
/* Not AJAX use return*/
}

PHP echo within a Javascript file

So the problem is as follows:
I want to dynamically echo a javascript thing with PHP. This echo needs to be (or work with) another javascript file where the echo'd value is used to call a function when the ID is clicked.
However when the page is loaded and the document.getElementById things are added (and they are correct) when the element is clicked, the console tells me that fplaying is undefined
PHP File
<?php
mysql_connect ("localhost", "root", "") or die ("We couldn't connect!");
mysql_select_db ("dr");
mysql_query ("SELECT * FROM songs");
$result = mysql_query ("SELECT * FROM songs");
while ($row=mysql_fetch_array($result)) {
$source = $row ['audiosource'];
echo "
document.getElementById('$source').onclick = fplaying
";
}
?>
JS File
$(function() {
console.log( "ready!" );
function fplaying () {
alert ("test");
}
});
I am not sure if this can be done with php and this is probably not the answer you are looking for.But long comments are not recommended so I just posted as an answer.
It is possible to do, I have done when I was new to Web Developments (With ASP.Net), but still this indicates an improper architecture. JavaScript, that you are using, is a client side script and thus should be accompanied with proper AJAX structure to do such thing. Server should only be responsible to send proper response based on request, not dictate how a page should behave on client side.
Some thing like -
var play = function(){
...//code to play
};
$.ajax({
url: ..//url to php page
type: ...
...,
success: function(data){
...//data responded by php page
play();
},
error: function(){
}
});
I used syntax for jQuery. There are other libraries too.
This is very simple. Try this.
echo " <script> ";
echo "document.getElementById('$source').onclick = fplaying ";
echo "</script>";
I don't think
document.getElementById('$source').onclick = fplaying
will find the function as fplaying is undefined.
Try:
var fplaying = function() {
alert ("test");
}
instead of
function fplaying () {
alert ("test");
}
As in the JS you are printing through PHP only sets the onclick event for an element with that ID which exists somewhere else on the page I think. So, much better way of doing this would be define a class in that clickable item
<button id='<?php echo $source; ?>' class='click-me'>Click Me</button>
Then in JS use this:
$('.click-me').on('click',function(){
alert($(this).attr('id'));
});
Let's suppose you have a collection, coming from a db query: $collection and consists of associative arrays, with a unique id
Now, you are obviously going to display these objects and ask for a user to do something with them, your fplay function. What you must do, is echo whichever parts of the items you need and somehow pass in the html the item id.
So, the php part which will construct your html would be something like:
echo "<ul>";
$id = $item['id'];
foreach ($collection as $item){
echo '<li><a onclick="return fplaying(' + $id + ')" href="#" class="btn"></li>';
}
echo "</ul>";
Then, your js function would use the id as a parameter and do whatever you need:
function fplaying (id) {
alert ("your id is " + id);
}
$source = $row ['audiosource'];
echo '<div id="'.$source['id'].'" class="sourceDiv">'.$source['name'].'</div>';
then go to your js file and add this --you don't have to do that in php
$(document).ready(function(){
$('.sourceDiv').click(function(){alert($(this).attr('id'))});
});
Obviously your declaration of fplaying() is delayed and in addition its locally defined, only.
$(function() {
console.log( "ready!" );
function fplaying () {
alert ("test");
}
});
In that code fplaying is dropped as soon as the outer function has finished. Try binding that fplaying to your window instead.
$(function() {
console.log( "ready!" );
window.fplaying = function() {
alert ("test");
};
});
To illustrate this additionally:
function a() {
function fplaying() {
alert("Hi");
}
fplaying();
}
a();
will display alert box.
function a() {
function fplaying() {
alert("Hi");
}
}
a();
fplaying();
won't show alert box for fplaying() is visible in scope of a(), only, and thus it's undefined as in your case.
function a() {
window.fplaying = function() {
alert("Hi");
};
}
a();
fplaying();
will show alert box for now fplaying() is declared as method of object window more or less serving as global scope, too.
For it's delayed using $(function() { ... }); make sure invoking code as rendered by PHP isn't running before document has loaded. But that doesn't seem to be an issue according to your spare information on context.
Okay, from what I understand of your problem:
Your php creates a html file that has an element with id="the value of $source" and you want it to play a sound on click.
If you want to create a piece of javascript like you did, you could try:
echo ""
while ($row=mysql_fetch_array($result)) {
$source = $row ['audiosource'];
echo "
document.getElementById('$source').onclick = fplaying()
";
}
echo "</script>"
That should make the browser recognize the script as javascript and execute it. Make sure this is printed to the html after the part of the page with the elements you're referring to is printed to the html. Otherwise the script might run before the relevant part of the page is loaded in the browser.

Categories

Resources