AJAX response using Jquery (with zend framework) contains unwanted HTML Code - json

Currently, the following code works as intended but if I add an echo such as "LANG: en" anywhere in the code (let's say in the bootstrap), the following code won't work anymore and I get this ajax request response :
<br/>LANG : en{"response":true,"id":13}
(the ajax response contains the echo + json array ) and therefore I'm not able to print the id (it will print : undefined when i will try to access to data.id).
My question is : How can I print my debug info and still manage to perform ajax requests ?
Here is my code in the controller :
public function init()
{
$this->_helper->ajaxContext->addActionContext('retrievecategories', 'json')->initContext();
}
public function retrievecategoriesAction()
{
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true);
if ($this->getRequest()->isXmlHttpRequest()) {
if (isset($_POST['id']))
$id = $_POST['id'];
$id+=1;
echo json_encode(array('response' => true, 'id' => $id));
}
}
My js code :
jQuery(function(){
var obj = {"id":12};
jQuery.ajax({
url: '/search/retrievecategories?json',
type: 'post',
data: obj,
dataType: 'json',
success: function(data){
var id = data.id;
alert(id);
},
error: function(data){
var id = data.id;
alert(id);
}
});
});
I hope I was clear enough. Thank you for your time !

If you echo anything but the JSON object, the JQuery parser will fail because the response is no longer a valid JSON. you could make a custom parser which interprets the response text and takes away the debug info leaving the JSON object, or you can include the debug info in the array you encode.
json_encode(array('data'=>'data','debug'=>'debug info'))
Then you detect if the debug field is present and after a console.log() or alert() you delete it form the object.

I would strongly recommend that you read about firePHP. It uses the same console that Firebug uses to display debug information from your php code. It is really simple to use with the Zend_Log.

Related

How to JSON parse using form.errors.as_json() in Django return JsonResponse(data)

In Django, I tried using form.errors.as_json() to get all form errors and here is sample json data strings.
{"password2":[{"message": "This password is too short. It must
contain at least 8 characters.","code":"password_too_short"}]}
I wanted to loop and get all under "message" key in json so I can use it to notify the user after ajax call.
Thanks
Anyways, I just resolved my issue and just wanted to share what I did.
views.py
if form.is_valid():
...
else:
# Extract form.errors
errMsg= None
errMsg = [(k, v[0]) for k, v in form.errors.items()]
return JsonResponse(errMsg)
Ajax Event
$.ajax({
method: "POST",
url: '\your_url_here',
data: $form.serialize(),
cache: false,
dataType: "json",
beforeSend: function(){
//Start displaying button's working animation
//Do some button or loading animation here...
}
},
success: function(jResults)
{
//This line is to remove field name display
var strErr = jResults + ''; //make json object as string
strErr = strErr.split(",").pop();
alert(strErr);
}
});
Hope this help to anyone out there facing similar issue. By the way, I'm using Django 2.0 and Python 3.6+
Thanks
MinedBP
The correct answer should be:
return HttpReponse(form.errors.as_json(), status=400).
In the AJAX call you can get the content doing:
`$.post("{% url 'your_url'%}", your_payload).done(function(data) {
do_something();
}).fail(function(xhr){
// Here you can get the form's errors and iterate over them.
xhr.responseText();
});`
You are sending a 200 HTTP response, that it is wrong, you should return a 400 HTTP response (Bad request), like Django do without AJAX forms.

cakephp 3.x _serialize key not working

I an trying to return json from a cakephp 3.1 controller function. My problem is that no matter what I do with the _serialize flag, the response is always that there is a missing view template file.
In the cake docs it says to set the _serialize flag if you do not need to use a template to format the response. Cake Docs on View _serialize
Below is the Javascript on the client side that initializes the process
function save_activity( mod, act, resp ) {
$.ajax({
method: 'POST',
url: '/activities/saveActivity',
data: {
'module' : "example1",
'activity_name' : "example2",
'response' : "example3"
},
dataType: 'json',
error: function( xhr, status, error ){
alert( status + error );
},
success: function( data, status, xhr ){
alert( status + data.success );
}
});
}
The Controller code that handles the json from the client.
public function saveActivity()
{
$user = $this->Auth->user();
//This line does not seem to do anything
//$this->request->input('json_decode', 'true');
//Debugger::log($this->request->data);
$activityTable = TableRegistry::get('Activities');
$activity = $activityTable->newEntity();
$activity->user_id = $user['id'];
$activity->module = $this->request->data('module');
$activity->activity_name = $this->request->data('activity_name');
$activity->response = $this->request->data('response');
//These lines do not have any effect
//$this->RequestHandler->renderAs($this, 'json');
//$this->response->type('application/json');
//$this->viewBuilder()->layout(null);
//$this->render(false);
$msg = '';
if ($activityTable->save($activity)) {
$msg = 'Activity Stored';
} else {
$msg = 'Activity Not Stored';
}
$this->set(['response' => $msg]);
//comment or uncomment this line and it makes no difference
//as it still returns a json response about a missing template.
$this->set('_serialize', true);
}
The error message I get when I include or remove the _serialize flag.
"Template file "Pages\json\module1\activity4.ctp" is missing."
Anyone have any insight into this mechanims? The workaround I have found is to include the template file... but this means I will have to generate a few dozen essentially empty template files to handle all the places this call is generated from.
Any help please?
Problem cause:- Violation of assumption.
My assumption was that the saveActivity method was being executed. While the reality was that AuthComponent was failing to allow access to that method and the default handler was being run instead, then the default view template was being looked for... and failing.
I found this by looking at the stack track attached to the error message in the returned page via devTools. I should also have verified this assumption with some simple trace logging calls. I already had the clue when I commented out the "$this->set('_serialize', true);" and nothing changed.
Then the simple solution was to authorise the method in the controllers beforeFilter:
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Auth->allow('saveActivity');
$this->Auth->allow('getActivity');
$this->eventManager()->off($this->Csrf);
}
Thanks for the assist ndm.

Backbone model .toJSON() doesn't work after .fetch()

Good day! I need to render a model's attributes to JSON so I can pass them into a template.
Model:
var UserInfo = Backbone.Model.extend({
url: appConfig.baseURL + "users/",
});
Template:
<script type="text/html" class="template" id="profile-form">
<h2 class="ui-li-heading"><%= username %></h2>
<p class="ui-li-desc"><strong><%= phone %></strong></p>
</script>
View:
var ProfilePageView = Backbone.View.extend({
events: {
'click #edit': "edit"
},
initialize: function () {
this.template = $.tpl['profile-form'];
var user = new UserInfo()
user.fetch({
data: $.param({email: localStorage.getItem('user_email')}),
type: 'POST'
});
console.log(user) //returns correct object with attrs
console.log(user.toJSON()) //returns empty object
},
render: function (eventName) {
$(this.el).html(this.template());
},
edit: function () {
window.workspace.navigate('#account/edit', { trigger: true});
}
});
When i put in console something like this, user.toJSON() returns correct data
var user = new UserInfo();
user.fetch({
data: $.param({email: localStorage.getItem('user_email')}),
type: 'POST'
});
But when i put it to my view, its returns Object {}.
Where is a mistake or tell me how can differently pass to the template data received from the server in json format? Thanks!
You appear to have two problems. fetch is asyncronous, so you need to use a callback to use the information. But first, an explanation about toJSON. .toJSON() doesn't actually return a JSON string, it returns an object that is what you want JSON to stringify. This allows you to modify the toJSON method to customize what attributes will be taken from your model or collection and added to the JSON string representation of your model. Here is a quotation from the Backbone.js docs:
toJSON collection.toJSON([options])
Return a shallow copy of the model's attributes for JSON
stringification. This can be used for persistence, serialization, or
for augmentation before being sent to the server. The name of this
method is a bit confusing, as it doesn't actually return a JSON string
— but I'm afraid that it's the way that the JavaScript API for
JSON.stringify works.
So you should replace this line in your code
console.log(user.toJSON())
with this one
console.log(JSON.stringify(user))
The object that you saw was returned by toJSON will then be turned into JSON.
Now, even after you do that, it won't work properly, because you will execute the console.log before you get the data for your model from fetch. fetch is asynchronous, so you need to call any code you want to be executed after the fetch is done in the success callback:
user.fetch({
data: $.param({email: localStorage.getItem('user_email')}),
type: 'POST',
success: function(){
console.log(user);
console.log(JSON.stringify(user));
}
});

Parse JSON returned from NODE.js

I’m using jQuery to make an AJAX call to Node.js to get some JSON. The JSON is actually “built” in a Python child_process called by Node. I see that the JSON is being passed back to the browser, but I can’t seem to parse it—-although I can parse JSONP from YQL queries.
The web page making the call is on the same server as Node, so I don’t believe I need JSONP in this case.
Here is the code:
index.html (snippet)
function getData() {
$.ajax({
url: 'http://127.0.0.1:3000',
dataType: 'json',
success: function(data) {
$("#results").html(data);
alert(data.engineURL); // alerts: undefined
}
});
}
server.js
function run(callBack) {
var spawn = require('child_process').spawn,
child = spawn('python',['test.py']);
var resp = '';
child.stdout.on('data', function(data) {
resp = data.toString();
});
child.on('close', function() {
callBack(resp);
});
}
http.createServer(function(request, response) {
run(function(data) {
response.writeHead(200, {
'Content-Type':
'application/json',
'Access-Control-Allow-Origin' : '*' });
response.write(JSON.stringify(data));
response.end();
});
}).listen(PORT, HOST);
test.py
import json
print json.dumps({'engineName' : 'Google', 'engineURL' : 'http://www.google.com'})
After the AJAX call comes back, I execute the following:
$("#results").html(data);
and it prints the following on the web page:
{“engineURL": "http://www.google.com", "engineName": "Google"}
However, when I try and parse the JSON as follows:
alert(data.engineURL);
I get undefined. I’m almost thinking that I’m not actually passing a JSON Object back, but I’m not sure.
Could anyone advise if I’m doing something wrong building the JSON in Python, passing the JSON back from Node, or simply not parsing the JSON correctly on the web page?
Thanks.
I’m almost thinking that I’m not actually passing a JSON Object back, but I’m not sure.
Yes, the ajax response is a string. To get an object, you have to parse that JSON string into an object. There are two ways to do that:
data = $.parseJSON(data);
Or, the recommended approach, specify dataType: 'json' in your $.ajax call. This way jQuery will implicitly call $.parseJSON on the response before passing it to the callback. Also, if you're using $.get, you can replace it with $.getJSON.
Also:
child.stdout.on('data', function(data) {
resp = data.toString();
// ^ should be +=
});
The data event's callback receives chunks of data, you should concatenate it with what you've already received. You probably haven't had problems with that yet because your JSON is small and comes in a single chunk most of the time, but do not rely on it, do the proper concatenation to be sure that your data contains all the chunks and not just the last one.

jQuery.getJSON and jQuery.parseJSON return [object Object]?

EDIT: I've gotten the "famous question" badge with this question, so I figured I'd come back to it and stick what happened to me right at the very tippy top for people searching it to get an answer right away.
Basically, I was new to JSON. JSON is an object (obviously), as it contains all kinds of stuff! So I was like "Hey, javascript, just pop up an alert with all of this JSON data", expecting it to give me the JSON data as a string. But javascript doesn't do that (which is good!), so it was like "Hey, this is how we display objects, [object Object]".
What I could've done is something like alert(obj.DATA[0][1]) and it would've shown me that bit of the object.
What I really wanted was to verify that I was making good JSON data, which I could've checked with JSON.stringify.
Anyway, back to our regularly scheduled questions!
I'm trying to get some JSON data with an ajax call, but jQuery doesn't seem to like my JSON.
if I do something like:
function init2() {
alert("inside init2");
jQuery.ajax({
url: "/Mobile_ReportingChain.cfm",
type: "POST",
async: false,
success: function (data) {
alert(data);
var obj = jQuery.parseJSON(data);
alert(obj);
}
});
}
I get this as from alert(data):
{"COLUMNS":["MFIRST_NAME","MLAST_NAME","MMDDL_NAME","MEMPLY_ID","MAIM_NBR","EMPLY_ID"],
"DATA":[
["FNAME1 ","LNAME1 ","MI1 ","000-14-7189","026-0010","000-62-7276"]
,["FNAME2 ","LNAME2 ","MI2 ","000-01-2302","101-1850","000-14-7189"]
,["FNAME3 ","LNAME3 ","MI3 ","000-91-3619","102-1000","000-01-2302"]
,["FNAME4 ","LNAME4 ","MI4 ","000-25-9687","102-1000","000-91-3619"]
]}
which JSONLint says is valid json. alert(obj) gives me this, however:
[object Object]
adding dataType: "json" or "text json" just makes it report [object Object] at alert(data).
I'd really like to get this figured out, does anyone know why it's doing this? I'm pretty new at jQuery, my goal is to get an array for each of the columns. The same code I'm using has worked on a different page it looks like, which is what's bothering me the most.
The alert() function can only display a string of text. As its only parameter it takes a string or an object. The object will however be converted into a string that can be displayed.
When fetching JSON through jQuery, the $.ajax() method will automatically parse the JSON and turn it into a JavaScript object for you. Your data variable is therefor a JavaScript object, and not a JSON string as one might expect.
Since alert() only can display strings, when trying to alert your data object, your object will be turned into its string representation. The string representation of a JavaScript object is [object Object].
For debug-purposes you can use console.log(data) instead. You can then inspect the object and its content through the console in your browsers developer tools.
function init2() {
jQuery.ajax({
url: "/Mobile_ReportingChain.cfm",
type: "POST",
dataType: "json",
async: false,
success: function (data) {
console.log(data);
}
});
}
If you for some reason still want to alert the JSON-data, then you would have to turn your data object back into a JSON-string. To do that you can make use of JSON.stringify:
alert(JSON.stringify(data));
it wants a string
var obj = $.parseJSON(JSON.stringify(data));
try sending that object to console.log. You'll get a clearer picture what does it contain.
Also, put dataType: 'json' and remove parseJSON because it's all the same.
This is how it's supposed to work. Your JSON becomes a javascript object. You can then manipulate that object as a regular javascript object.
data.COLUMNS for instance should return an array.
[object Object] is the string representation of a javascript object.
Try accessing properties of the object.
alert(data.COLUMNS[0]);
jQuery.parseJSON will convert the json string into json object so alert(obj) will show you [object Object] since it is an object.
If you want to see what obj contains then use console.log(obj) and then check console log message.
$.getJSON( "UI/entidades.json.php", function(data){
result = JSON.stringify(data);
alert(result)
console.log(result)
})
(I knows this is an jquery problem; but just bear with me for a min. so that i can explain why this problem occurred to me in the first place).
I wanted to fill in the gaps made my deletion of records in my MySQL table ( primary key that was auto increment. So when records where deleted in between my id had missing keys. I though some mechanism to show those missing keys. So i created the code that created an array through a loop then deleted those keys that were present and echo backed that array (of course json_encode that array).
But to my amazement what ever I did it always end up giving me [object Object].
It baffled me a lot that were was the problem.
Solution: Just realigning the array and all my problem gone.
Below I would give an simplified example.
<!DOCTYPE html>
<html>
<head>
<script src="../js/jquery/jquery3.x/jquery-3.3.1.min.js"></script>
<title></title>
<script type="text/javascript">
$(function () {
$('#generate').click(function () {
$.get('tmp2.php?tab=1', function (data) {
var retStr = '<table>';
var par = $.parseJSON(data);
$(par).each(function () {
retStr += '<tr><td>' + this + '</td></tr>';
});
retStr += '</table>';
$('#res').html(retStr);
});
});
});
</script>
</head>
<body>
<input type="button" value="generate" id="generate" />
<div id="res"></div>
</body>
</html>
And the controller
<?php
if (!empty($_GET['tab'])) {
$ids = array();
for ($i = 0; $i < 50; $i++)
$ids[] = $i;
for ($i = 0; $i < 50; $i = $i + 2)
unset($ids[$i]);
// echo json_encode($ids); // this will generate [object Object]
$res = array();
foreach ($ids as $key => $value) {
$res[] = $value;
}
echo json_encode($res);
exit();
}
?>