Here is the example delete options I'm using using in a jqGrid. It works just fine and my serverside scripts are working perfectly. The records get deleted, but there is something that goes wrong after the response from the server is received.
// Del Options
{
mtype: "POST",
modal: true,
url: "/internal/backupmanagement/backupmanager/deleteMySQLDB",
reloadAfterSubmit: false,
onclickSubmit: function () {
var post = $("#grid_" + o.id).jqGrid("getGridParam", "postData");
var server = post.serverID;
$.openDialog("load", "Deleting old database entry. Please wait...");
var selrow = $("#grid_" + o.id).jqGrid("getGridParam", "selrow");
var row = $("#grid_" + o.id).jqGrid("getRowData", selrow);
console.log("about to return", row, server);
return {
id: row.recid,
database: row.database,
server: server
};
},
afterSubmit: function (response, postdata) {
response = eval("(" + response.responseText + ")");
console.log(response);
return [true, "success"];
},
afterComplete: function (response, postdata, formid) {
response = eval("(" + response.responseText + ")");
var selrow = $("#grid_" + o.id).jqGrid("getGridParam", "selrow");
$("#grid_" + o.id).jqGrid("delRowData", selrow);
if (response.error == 0) {
$.openDialog("info", "Successfully deleted " + postdata.database + ".");
} else {
$.openDialog("info", "And error occured - " + response.msg + ".");
}
}
}
I get the following error before the afterComplete event is fired in the grid :
Uncaught TypeError: Object [object Array] has no method 'split'
So it seems something is being returned as an object when it was expecting a string. I'm not sure if my response from the server is formatted correctly and I wasn't able to find any expected response in the documentation either.
* UPDATE *
Server-side code as requested. I've just included the controller function that interacts with the jqGrid, the rest is working and happening further on in the application.
function deleteMySQLDB()
{
if (IS_AJAX) {
if (($this->Application->deleteMySQLDBData(
$_POST["id"],
$_POST["database"],
$_POST["server"]
)) === false) {
echo json_encode(
array(
"error" => 1,
"msg" => "Failed Deleting record from database: "
.$this->Application->error
)
);
return false;
}
echo json_encode(
array(
"error" => 0,
"msg" => "success"
)
);
return true;
} else {
header("Location: /");
}
}
I hope this helps to see what I'm currently returning to the grid.
* UPDATE *
What I have done is changed the source in the jqGrid plugin to include a toString() on the value before preforming the split.
On line 331 of jquery.jqGrid.min.4.3.1 :
var A=[];A=H.split(",");
Changed to :
var A=[];A=H.toString().split(",");
It seemed like a harmless change in the grand scheme of things and avoids arrays to be attempted to get split. Thanks a lot for the help guys. You certainly pointed me in the right place to start looking, Oleg!
Let's suppose that the origin of the described error is the code of your afterComplete callback. I think that you are using it in a wrong way. I don't understand some parts of the code, the part (testing of response.error) should be moved in afterSubmit.
The main problem will be clear if you examine the lines of code where afterComplete callback will be called. It will be executed inside of setTimeout with 0.5 sec delay. At the time new data in the grid can be loaded (or could be loading). So it would be wrong to use methods like delRowData and the value of selrow could be changed now.
I would strictly recommend you additionally don't use eval function. Instead of the line
response = eval("(" + response.responseText + ")");
it will be correct to use
response = $.parseJSON(response.responseText);
The code of onclickSubmit callback could be improved if you would use the fact that this inside of the callback (like the most other callbacks o jqGrid) are initialized to DOM element of the grid. So to get selrow option of the grid you can use
var selrow = $(this).jqGrid("getGridParam", "selrow");
instead of
var selrow = $("#grid_" + o.id).jqGrid("getGridParam", "selrow");
Another fact is onclickSubmit will be called by jqGrid with two parameters: options and postdata. The parameter postdata is rowid if you use don't use multiselect: true. In case of usage of multiselect: true the value of postdata parameter of the callback can be comma separated list of rowids of the rows which will be deleted. So the usage of postdata is better as the usage of selrow.
I"m making a good guess since you didn't include your server side code.
On the server you can return something like:
return Json(new { success = false, showMessage = true, message = "Error - You can't have a negative value", title = "Error" });
Then on your client you can have something to display a message (in this example if there was an error)
afterComplete: function (response) {
var DialogVars = $.parseJSON(response.responseText); //parse the string that was returned in responseText into an object
if (!DialogVars.success || DialogVars.showMessage) {
showDialog($('#Dialog'), DialogVars.message, DialogVars.title);
}
} //afterComplete
Related
I have an Ajax request that runs fine for the most part, it expects a json return and processes it accordingly. However if my PHP server throws an Notice (or warning or error for that matter), it triggers the ajax fail function automatically, EVEN if the response contains the Json array as part of it (usually after the PHP notice)
For development purposes, I don't want to turn of these PHP notices, I was wondering if the ajax could still handle the PHP notice and actually realize that the json return array was also included as part of the return, and somehow trigger the "done" function instead.
Not that it really matters but here a cut down version of the my ajax code, where having a PHP Notice being output by the server automatically triggers the "fail" callback, instead of "done" callback.
function getTimeSlots() {
$("#reservationtimebuttonsplaceholder").hide();
$.post( "<?php echo Router::url(array('controller'=>'Bookings','action'=>'getMerchantAvailableTimeSlots_ajax')); ?>", $( ".reservationform" ).serialize(), function() {
$(".reservationtimebuttons").empty();
}, "json")
.done(function(data) {
var respstatus = data.status;
var message = data.message;
var failtype = data.failtype;
var timeslots = data.timeslots;
if (respstatus === false) {
$(".reservationtimebuttons").html(message)
}
if (respstatus === true) {
$.each(timeslots, function (dataKey, dataVal) {
$.each(dataVal, function(timeKey,timeVal){
$.each(timeVal,function(timePropKey, timePropVal){
btn_id_postfix = timePropKey.replace(/\:/g,"");
$output = "<button id=\"btn" + btn_id_postfix + "\" class=\"btn btn-grey btn-timeselection\" value=\"" + timePropKey + "\" type=\"button\">" + timePropVal + "</button>";
$(".reservationtimebuttons").append($output);
});
});
});
}
})
.fail(function() {
alert( "There was a problem getting the available timeslots! Please try again later" );
})
.always(function() {
});
}
you can use simple ajax call , and not specify "json" as part of it , then this will get anything that comes from the php into the response of your ajax call.
and then try to JSON.parse it , if this function cannot parse the reponse to JSON , this means reponse is not properly formated and that means you php code has maybe some error or warning ,
then you can check if the response has something like status , so it is what you want with no error , and if not , php has shoot some errors beside your response .
I have an Ajax script that makes a call to a php file on my server every twenty seconds.
The server then runs a simple mysql query to return the contents of a particular field.
If that field is blank I want the php file to echo the word "pending", which when caught by the success handler will recall the initial function. However if that field is not blank, it will contain a URL to which I want to redirect the user to. That field will update any where between 5 seconds and 5 minutes from the start of the first call and that time cannot be changed.
I think the main issue may be with my php file, in that I dont think it is echoing the data in a way that the success handler recognises. However I have detailed both parts of my code as whilst the success handler seems to be constructed correctly I am not 100% sure.
Very new to this, so apologies if I have not explained myself correctly but if anyone could assist that would be great:
UPDATE - for clarity what I am looking to achieve is as follows:
Ajax call to my php file.
PHP file queries database
If field queried contains no data echo the word "pending" to the ajax success handler (IF) which in turn recalls the original function / ajax call.
If field queried contains data (will be a URL) echo this result to the ajax success handler (ELSE)in a format that will redirect the user via window.location.assign(data).
FURTHER UPDATE
I managed to solve this question with using a combination of the advice from #mamdouhalramadan and #martijn
I also have changed setInterval to setTimeout as the poll function was causing responses to stack up should the server be running slowly and as such cause errors. I also added in cache: false and a further option in the success handler to take into account slightly different behaviour in IE:
AJAX
function poll() {
$.ajax({
url: 'processthree.php?lead_id='+lead_id,
type: "GET",
cache: false,
async: false,
success: function(data3) {
//alert("pending called " + data3)
if(data3.indexOf("pending") >-1 ){
setTimeout(poll, 20000);
}
else if ( (navigator.userAgent.indexOf('MSIE') != -1) ) {
//alert("Submit success - MSIE: " + data3);
parent.window.location.replace(data3);
}
else{
//alert("process three called " + data3)
window.top.location.assign(data3);
}
},
error: function(xhr, error){
//alert("Error");
//alert("Error: " + error + ", XHR status: " + xhr.status);
},
});
}
setTimeout(poll, 20000);
PHP
$query = ("SELECT column FROM table WHERE id = '$lead_id'") or die(mysql_error());
$result = mysql_query($query);
$return = array();
while($row = mysql_fetch_assoc($result))
{
$return = 'pending';
if($row['column'] != '')
{
$return = $row['column'];
}
}
echo $return;
I believe using json might help you out here, not to mention it is safer, like so:
function poll() {
$.ajax({
url: 'processthree.php?lead_id='+lead_id,
type: "GET",
dataType: 'json',//specify data type
success: function(data3) {
if(data3.res.indexOf("pending") >-1 ){
//rest of the code.....
then in your php:
$return = array();
while($row = mysql_fetch_assoc($result))
{
$return['res'] = 'pending';
if($row['column'] != '')
{
$return['res'] = $row['column'];
}
}
echo json_encode($return);
Note: use PDO or MYSQLI instead of mysql as it is deprecated.
I tell you what, getting AJAX to work is one pain in the wazoo! It took me ages to get a simple string to pass and then I got a json array working and felt good, now I've tried to make a little adjustment and broke the whole thing again. Why is following giving an ajax error and how can I get under the hood to see what's going on?
jQuery:
$('#upload_form option[value="addnew"]').click(function(){
// Show modal window
$('#add-new').modal('show');
// Get the class
var Classofentry = $(this).attr("class");
//console.log(Classofentry);
$('#add-new-submit').on('click', function(){
// Get new option from text field
var value = $('#add-new-text').val();
console.log(value);
$.ajax({
type: "POST",
url: "<?php echo site_url(); ?>main/change_options",
data: {new_option: value, new_option_class: Classofentry},
//dataType: "html",
dataType: "json",
error: errorHandler,
success: success
});
function success(data)
{
if (data[1]) // Only add new entry if unique
{
// Add new entry
//$('#animal_species').append("<option value='" + data + "'selected=\"selected\">" + data + "</option>");
$('#'+Classofentry).append("<option value='" + data[0] + "'selected=\"selected\">" + data[0] + "</option>");
//alert(data[0]);
}
else
{
// Select the nonunique value by emptying it and appending
$('#'+Classofentry).empty("<option value=''selected=\"selected\">" + data[0] + "</option>").append("<option value='" + data[0] + "'selected=\"selected\">" + data[0] + "</option>");
//alert(data[1]);
}
alert(data[1]);
//alert('Success!');
}
function errorHandler()
{
//alert('Error with AJAX!');
alert(data[0]);
}
$('#add-new-submit').unbind('click'); // This fixes the problem for multiple entries
$('#add-new').modal('toggle');
});
});
php:
public function change_options()
{
# Receives and sends back user-entered new option and adds it to database
# Get strings from ajax in view
$value = $_POST['new_option'];
$value_class = $_POST['new_option_class'];
#Make array to send to model
$value_array = array('Options' => $value);
$unique = true;
echo json_encode(array($value, $unique));
}
In the console I get: ReferenceError: data is not defined. I've spent the last couple days working on logic to determine $unique and now the ajax won't work, even when I strip it back to it's bare bones. What going on here?
Th code I posted should've worked. I found the issue and it wasn;t with ajax, it was with me passing the wrong thing to the model. Here's the working code, with the logic to determine $unique:
(BTW, this solves the problem posed in Form Validation in Codeigniter: using set_rules to check text input from a modal window without using Form Validation):
public function change_options()
{
# Receives and sends back user-entered new option and adds it to database
# Get strings from ajax in view
$value = $_POST['new_option'];
$value_class = $_POST['new_option_class'];
//print_r($value_class); die;
#Make array to send to model
$value_array = array('Options' => $value);
$unique = true;
$this->load->model('data_model');
$elements = $this->data_model->get_options($value_class);
foreach ($elements as $element)
{
if (preg_match("/$element/", $value, $matches))
{
$unique = false;
break;
}
}
# Add new option to dropdown in database
if ($unique) {$this->data_model->add_option($value_class, $value_array);}
//echo $value;
echo json_encode(array($value, $unique));
}
Turning off asynchronous requests in jQuery fixed the issue.
I have the following Javascript & AJAX request (using jQuery) in my page:
"use strict";
var hsArea, counter, hotspots, count;
counter = 4;
count = 0;
hotspots = {};
function fetchHotspotList() {
$.getJSON ('/alpha/engine/hotspots/gethotspot.php', {'type' : 'list'}, function(json) {
hotspots = json;
});
}
function displayHotspot(type, id, number) {
$.ajax({
url: '/alpha/engine/hotspots/gethotspot.php',
dataType: 'json',
data: {'type' : type, 'id' : id},
success: function(json) {
console.log(json);
var hotspot, extract;
extract = json.content;
extract = extract.replace(/<(?:.|\n)*?>/gm, '');
extract = extract.substring(0, 97);
extract = extract + "...";
json.content = extract;
hotspot = document.createElement("div");
hsArea.append(hotspot);
hotspot.setAttribute('class','hotspot');
hotspot.setAttribute('id','hotspot' + number);
$(hotspot).css('position', 'absolute');
$(hotspot).css('top', number * 100 + 100);
$(hotspot).css('left', number * 100 + 110);
hotspot.innerHTML = "<h1>"+ json.title + "</h1><p>" + json.content + "</p>";
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus, errorThrown);
}
});
}
function listHotspots() {
for(count = 0; count < counter; count++) {
(function(count) {
displayHotspot('scribble',hotspots[count], count);
count = count + 1;
})(count);
}
}
function loadHotspots() {
fetchHotspotList();
listHotspots();
}
$(document).ready(function() {
hsArea = $("#hotspotArea");
fetchHotspotList();
listHotspots();
});
(Sorry the formatting is a bit off!) - Now, the $(document).ready() function assigns the hsArea variable as it should, however, a combination of fetchHotspotList() and listHotspots() returns:
Uncaught TypeError: Cannot call method 'replace' of null
However, if in the Google Chrome Javascript console, I run:
loadHotspots();
it fetches the data from the AJAX request and displays it properly on the page. At first I thought the problem was that I Wasn't using the $(document).ready() handler, but adding it hasn't fixed it. Neither has using an onload handler inside of the body tag.
Any help would be greatly appreciated.
Regards,
Ben.
It's probably due to the fact that your listHotSpots function is called before fetchHotSpots returns (since it's an async call).
You're better off chaining the execution of listHotSpots to the completion of fetchHotSpots, like so:
function fetchHotspotList() {
$.getJSON ('/alpha/engine/hotspots/gethotspot.php', {'type' : 'list'}, function(json) {
hotspots = json;
listHotSpots();
});
}
You may be better off modifying listHotSpots to take the json data returned from your AJAX call. Hope this helps!
I am trying to create a little ajax chat system (just for the heck of it) and I am using prototype.js to handle the ajax part.
One thing I have read in the help is that if you return json data, the callback function will fill that json data in the second parameter.
So in my php file that gets called I have:
header('Content-type: application/json');
if (($response = $acs_ajch_sql->postmsg($acs_ajch_msg,$acs_ajch_username,$acs_ajch_channel,$acs_ajch_ts_client)) === true)
echo json_encode(array('lastid' => $acs_ajch_sql->msgid));
else
echo json_encode(array('error' => $response));
On the ajax request I have:
onSuccess: function (response,json) {
alert(response.responseText);
alert(json);
}
The alert of the response.responseText gives me {"lastid": 8 } but the json gives me null.
Anyone know how I can make this work?
This is the correct syntax for retrieving JSON with Prototype
onSuccess: function(response){
var json = response.responseText.evalJSON();
}
There is a property of Response: Response.responseJSON which is filled with a JSON objects only if the backend returns Content-Type: application/json, i.e. if you do something like this in your backend code:
$this->output->set_content_type('application/json');
$this->output->set_output(json_encode($answer));
//this is within a Codeigniter controller
in this case Response.responseJSON != undefined which you can check on the receiving end, in your onSuccess(t) handler:
onSuccess:function(t) {
if (t.responseJSON != undefined)
{
// backend sent some JSON content (maybe with error messages?)
}
else
{
// backend sent some text/html, let's say content for my target DIV
}
}
I am not really answering the question about the second parameter of the handler, but if it does exist, for sure Prototype will only provide it in case of proper content type of the response.
This comes from Prototype official :
Evaluating a JavaScript response
Sometimes the application is designed
to send JavaScript code as a response.
If the content type of the response
matches the MIME type of JavaScript
then this is true and Prototype will
automatically eval() returned code.
You don't need to handle the response
explicitly if you don't need to.
Alternatively, if the response holds a
X-JSON header, its content will be
parsed, saved as an object and sent to
the callbacks as the second argument:
new Ajax.Request('/some_url', {
method:'get', onSuccess:
function(transport, json){
alert(json ? Object.inspect(json) : "no JSON object");
}
});
Use this functionality when you want to fetch non-trivial
data with Ajax but want to avoid the
overhead of parsing XML responses.
JSON is much faster (and lighter) than
XML.
You could also just skip the framework. Here's a cross-browser compatible way to do ajax, used in a comments widget:
//fetches comments from the server
CommentWidget.prototype.getComments = function() {
var commentURL = this.getCommentsURL + this.obj.type + '/' + this.obj.id;
this.asyncRequest('GET', commentURL, null);
}
//initiates an XHR request
CommentWidget.prototype.asyncRequest = function(method, uri, form) {
var o = createXhrObject()
if(!o) { return null; }
o.open(method, uri, true);
o.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
var self = this;
o.onreadystatechange = function () {self.callback(o)};
if (form) {
o.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
o.send(makePostData(form));
} else {
o.send('');
}
}
//after a comment is posted, this rewrites the comments on the page
CommentWidget.prototype.callback = function(o) {
if (o.readyState != 4) { return }
//turns the JSON string into a JavaScript object.
var response_obj = eval('(' + o.responseText + ')');
this.comments = response_obj.comments;
this.refresh()
}
I open-sourced this code here http://www.trailbehind.com/comment_widget