I'm following a tut from here but I can't get the ajax to work, also I did checked the headers in chromes console, but I didn't see a text/json header as well! Could you please help me with it I can't figure it out.
Thanks in advance.
main.py
class Main(webapp2.RequestHandler):
def get(self):
if self.request.get('fmt') == 'json':
data = {'name' : 'sam', 'age': 25}
self.response.headers['content-type'] = 'text/json'
self.response.write(json.dumps(data))
return
self.templateValues = {}
self.templateValues['title'] = 'AJAX JSON'
template = jinja_environment.get_template('index.html')
self.response.write(template.render(self.templateValues))
app = webapp2.WSGIApplication([('/.*', Main),], debug=True)
index.html
<input type ="button" id="getitbutton" value="click button"/>
<div id= "result">
</div>
js script
<script type="text/javascript" >
function showData(data){
console.log(data.name);
$('#result').html(data.name)
}
function handleclick(e){
$.ajax('/',{
type: 'GET',
data: {
fmt: 'json'
}
success: showData
});
}
$(document).ready(function(){
$('#getitbutton').on('click', handleclick);
});
</script>
There are some problems with the current browsers, especially IE which does not send the text/json content type header. So I learned not to depend on the headers.
Instead my solution to this is like this:
The js ajax function:
function ajax(url,obj,callback){
var xhr=new XMLHttpRequest;
xhr.onreadystatechange=function(){
if(this.readyState==4){
if(callback){
callback(this.responseText);
}
}
}
xhr.open("POST",url);
xhr.send(JSON.stringify(obj));
}
Then on the server side, I read directly from the Request Body (sorry for the Go code, but I think you can also get the Request body from Python runtime?):
// read the request body
body, _ := ioutil.ReadAll(httpRequest.Body)
// parse the json payload
var user struct {
Email string
Password string
}
json.Unmarshal([]byte(body), &user)
Hope this helps
Related
Solution:
My mistake was that the url attribute doesn't just add the string given to 127.0.0.1 but to the current url, and so the url for the Like view was supposed to be 127.0.0.1/article/article_id/like-article-commm
I wrote a django app that has articles and im trying to add a like functionality, I added the code in the bottom and nothing happens. No error just nothing in the database or the html code changes. Any idea what is the problem?
The relevent part of the html/javascript code:
<head>
<script src="https://code.jquery.com/jquery-3.4.1.js" integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU=" crossorigin="anonymous"></script>
</head>
<button id='like-button' color = 'black'> Like </button>
<script type="text/javascript">
$('#like-button').click(function(){
var article_id = '{{ article.id }}';
var user_id = '{{ user.id }}';
var like_dislike = True;
$.ajax(
{
type:"GET",
url: "like-article-commm",
data:{
article_id: article_id,
user_id: user_id,
like_dislike: like_dislike
},
success: function( data )
{
$('#like-button').css('color', 'blue'); } }) });
</script>
The like-article-comm View:
def Like_Article_View(request):
if request.method == 'GET':
article_id = int(request.GET['article_id'])
likedarticle = Article.objects.get(id = article_id)
user_liked_id = int(request.GET['user_id'])
userliked = User.objects.get(id = user_liked_id)
like_dislike_0 = request.GET['like_dislike']
like_object_list = Like_Article.objects.filter(article_liked = likedarticle, user_liked = userliked)
if like_object_list.count() > 0:
existing_like = like_object_list.filter()
if existing_like.like_dislike == like_dislike_0:
return HttpResponse('success')
existing_like.like_dislike = like_dislike_0
existing_like.save()
like_new_object= Like_Article(article_liked=likedarticle, user_liked=userliked, like_dislike=like_dislike_0)
like_new_object.save()
return HttpResponse('success')
else:
return HttpResponse("unsuccesful")
urls.py file:
from django.urls import path
from . import views
from .views import ArticleListView, ArticleDetailView, ArticleCreateView, ArticleUpdateView, ArticleDeleteView
urlpatterns = [
path('', ArticleListView.as_view(), name="home-comm"),
path('article/<int:pk>/', ArticleDetailView.as_view(), name="article-comm"),
path('like_article/', views.Like_Article_View, name='like-article-commm'),
]
I can add like objects to the database manually.
--update--
After some discussion, we figure out that frontend ajax is not communicating with the backend properly. With chrome devtools we managed to pin point where the issue lies.
have you enabled CORS cross site resource sharing?
I have a REST API that I am using in a mobile application to register/store data into a Mongo database. I would now like to view the data stored in the DB on a webpage.
I know that I basically have all of the functionality already (the login request used in my mobile application) but I am so confused on how to call my REST from my HTML page.
Something like this: How to call a REST web service API from Javascript button Handler? ?
I am also confused on how/where I should be creating my html page. Any help is appreciated.
Thanks, Joe
Typically When user would like to get data from the server. client need to send a request to the server and get a response. Usually programmer will bind a request function with an specific element and events.
In this case you need to bind a request function with form element. As you didn't mention which event you want to happen, so I couldn't tell exactly solution.
The following code is a simple code that call REST API when user type on a text input, and show the result below the input text
Note that replace "URL" with your API call.
<!DOCTYPE html>
<html>
<body>
<form>
Keyword:<br>
<input type="text" name="keyword" onkeyup="callREST()"><br>
</form>
<div id="response"></div>
<script>
function callREST() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("response").innerHTML = this.responseText;
}
};
xhttp.open("GET", "URL", true);
xhttp.send();
}
</script>
</body>
</html>
This is how you do it...
HTML Code:
<form id="form" onsubmit="return setAction(this)">
<input name="senderEmail" type="email" placeholder="Email" required>
<textarea name="senderMessage" cols="30" rows="10" placeholder="Message.." required></textarea>
<button type="submit">Send message</button>
</form>
Javascript:
function setAction(form) {
const url = 'https://example.com/xyz?';
const andSign = '&';
const senderParameter = 'sender='+form.senderEmail.value;
const bodyParameter = 'body='+form.senderMessage.value;
const newUrl = url+senderParameter+andSign+bodyParameter;
fetch(
newUrl,
{
headers: { "Content-Type": "application/json" },
method: "POST",
body: ""
}
)
.then(data => data.json())
.then((json) => {
alert(JSON.stringify(json));
document.getElementById("form").reset();
});
return false;
}
This also resets your form after a successful api call is made.
I have multiple input tags, my task is to collect the values entered by the user and send it back to the server. I am using Django as my framework. I am successful in sending the data to the client side (javascript).
To return back the data from javascript function to my python function, I used XMLHttpRequest.
I have added my code below:
<html>
<head>
<style>label{ text-align:center; width:250px; color:blue; display:inline-block}</style>
<script type="text/javascript" src="'+url_read+'"></script>
<script>
function submit_this()
{
var i,j;var arr=[];
for(i=0; i<Hello.length; i++)
{
arr[i]=[];
for(j=0;j<Hello[i].length; j++)
{
arr[i].push(document.getElementById(Hello[i][j]).value);
}
}
alert(document.getElementById(Hello[1][0]).value);
xmlHttpReq = new XMLHttpRequest();
xmlHttpReq.open('POST', '/button_click',true);
xmlHttpReq.send('w=' + encodeURI(arr));
}
</script>
</head>
<body>
<center>
<button id="submit_button" onclick="submit_this();" value="Submit">Submit</button>
</center>
</body>
</html>
The above code is stored in a string called html_string.
Hello is a json object read from the file denoted by the varible url_read. It was dumped using Python.
The plan was to use HttpResponse to send the html_string and render the html page in return.
I understand that I need to make one POST function in one of the classes in views.py. But unable to understand how to approach this problem.
I have to somehow send the javascript data structure named arr back to the server side. The main doubt is where can I put my code where I can read the value posted by the javascript function.
I want to navigate to a new page once submit button has been pressed and in Django each url has a new function (in views.py) associated with it. Should I place it in that ?
Here is an example where in I am sending values to (Django)python server using JS, and receiving html rendered template.
I am using ul tag with id #Nearby to load html inside an html.
Ajax success is returning html from django view rendered through url endpoint '/getGopoints/'
template.html
<div class="row">
<div>
<ul id="Nearby">
</ul>
</div>
</div>
<script>
$(document).ready(function(){
$('#dataTables-example1').DataTable({
responsive: true
});
getLocation();
});
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
}
}
function showPosition(position) {
$.ajax({
url : '/getGopoints/', // the endpoint
type : 'GET', // http method
data : { 'lat' : position.coords.latitude,
'lon' : position.coords.longitude,
'csrfmiddlewaretoken': '{{csrf_token}}'
}, // data sent with the post request
// handle a successful response
success : function(data) {
$('#Nearby').html(data);
},
dataType: 'html'
});
}
</script>
urls.py
url(r'^getGopoints/$',views.getGopoints, name='getGopoints'),
views.py
def getGopoints(request):
lat = str(request.GET['lat'])
lon = str(request.GET['lon'])
pnt=fromstr('POINT(%s %s)' %(lon,lat))
with_in_distance = 20
go_points = GoPoint.objects.filter(point__distance_lte=(pnt, D(km=with_in_distance)))
context = RequestContext(request,
{'go_points':go_points,
'with_in_distance':with_in_distance,
})
return render_to_response('nearby.html',
context_instance=context)
This is a question in relation to this one.
In UPDATE II, I added a script based on Jamie's feedback.
UPDATE - tl;dr:
I created a fiddle with a temporary key so you guys can see the problem more easily: http://jsfiddle.net/S6wEN/.
As this question was getting too long, this is a summary.
I tried to use imgur API to update an image via cross domain XHR.
In order to abstract details in the implementation, I'm using Jquery Form Plugin (obviously, it's contained in the fiddle).
Works great in Chrome, Firefox, etc but it doesn't work in IE9.
The expected result is to update the image and retrieve image type.
You can still find the details below.
Thanks
I have this HTML:
<body>
<form id="uploadForm" action="http://api.imgur.com/2/upload.xml" method="POST" enctype="multipart/form-data">
<input type="hidden" name="key" value="MYKEY">
File: <input type="file" name="image">
Return Type: <select id="uploadResponseType" name="mimetype">
<option value="xml">xml</option>
</select>
<input type="submit" value="Submit 1" name="uploadSubmitter1">
</form>
<div id="uploadOutput"></div>
</body>
So basically, I have a form to upload an image to imgur via cross domain XHR. In order to manage the nasty details, I'm using Jquery Form Plugin, which works well. However, when I try to send an image to imgur and receive an xml response, it doesn't work as expected in IE9 (I haven't tested in IE8 but I don't expect great news). It works great in Chrome and Firefox. This is the javascript part:
(function() {
$('#uploadForm').ajaxForm({
beforeSubmit: function(a,f,o) {
o.dataType = $('#uploadResponseType')[0].value;
$('#uploadOutput').html('Submitting...');
},
complete: function(data) {
var xmlDoc = $.parseXML( data.responseText ),
$xml = $( xmlDoc );
$('#uploadOutput').html($xml.find('type'));
}
});
})();
In IE9 I receive the following errors:
SCRIPT5022: Invalid XML: null
jquery.min.js, line 2 character 10890
XML5619: Incorrect document syntax.
, line 1 character 1
I also used the example given in Jquery Form Plugin's page, which uses only Javascript but it doesn't help. Obviously, the first error referring to Jquery disappears but I can't obtain the expected results (in this case, image/jpeg in the div with id="uploadOutput" ).
When I look at the console in IE9, I get this:
URL Method Result Type Received Taken Initiator Wait Start Request Response Cache read Gap
http://api.imgur.com/2/upload.xml POST 200 application/xml 1.07 KB 7.89 s click 2808 93 5351 0 0 0
and as body response:
<?xml version="1.0" encoding="utf-8"?>
<upload><image><name/><title/><caption/><hash>xMCdD</hash>
<deletehash>Nb7Pvf3zPNohmkQ</deletehash><datetime>2012-03-17 01:15:22</datetime>
<type>image/jpeg</type><animated>false</animated><width>1024</width
<height>768</height><size>208053</size><views>0</views><bandwidth>0</bandwidth></image
<links><original>http://i.imgur.com/xMCdD.jpg</original
<imgur_page>http://imgur.com/xMCdD</imgur_page>
<delete_page>http://imgur.com/delete/Nb7Pvf3zPNohmkQ</delete_page>
<small_square>http://i.imgur.com/xMCdDs.jpg</small_square>
<large_thumbnail>http://i.imgur.com/xMCdDl.jpg</large_thumbnail></links></upload>
which is all fine, but for some reason, I can't process that information into the HTML page. I validated the XML, just to be sure that wasn't the problem. It is valid, of course.
So, what's the problem with IE9?.
UPDATE:
Another way to fetch XML which works in Chrome and Firefox but not in IE9:
(function() {
$('#uploadForm').ajaxForm({
dataType: "xml",
beforeSubmit: function(a,f,o) {
o.dataType = $('#uploadResponseType')[0].value;
$('#uploadOutput').html('Submitting...');
},
success: function(data) {
var $xml = $( data ),
element = $($xml).find('type').text();
alert(element);
}
});
})();
UPDATE 2:
<!DOCTYPE html>
<html>
<body>
<form id="uploadForm" action="http://api.imgur.com/2/upload.xml" method="POST" enctype="multipart/form-data">
<input type="hidden" name="key" value="00ced2f13cf6435ae8faec5d498cbbfe">
File: <input type="file" name="image">
Return Type: <select id="uploadResponseType" name="mimetype">
<option value="xml">xml</option>
</select>
<input type="submit" value="Submit 1" name="uploadSubmitter1">
</form>
<div id="uploadOutput"></div>
</body>
</html>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="jquery.form.js"></script>
<script>
(function() {
var options = {
// target: '#output1', // target element(s) to be updated with server response
//beforeSubmit: showRequest, // pre-submit callback
success: afterSuccess, // post-submit callback
complete: afterCompletion,
// other available options:
//url: url // override for form's 'action' attribute
type: 'POST', // 'get' or 'post', override for form's 'method' attribute
dataType: 'xml' // 'xml', 'script', or 'json' (expected server response type)
//clearForm: true // clear all form fields after successful submit
//resetForm: true // reset the form after successful submit
// $.ajax options can be used here too, for example:
//timeout: 3000
};
function process_xml(xml) {
var type = $(xml).find('type').text() ;
return type;
// Find other elements and add them to your document
}
function afterSuccess(responseText, statusText, xhr, $form) {
// for normal html responses, the first argument to the success callback
// is the XMLHttpRequest object's responseText property
// if the ajaxForm method was passed an Options Object with the dataType
// property set to 'xml' then the first argument to the success callback
// is the XMLHttpRequest object's responseXML property
// if the ajaxForm method was passed an Options Object with the dataType
// property set to 'json' then the first argument to the success callback
// is the json data object returned by the server
var $xml = process_xml(responseText);
console.log('success: ' + $xml);
}
function afterCompletion(xhr,status){
if(status == 'parsererror'){
xmlDoc = null;
// Create the XML document from the responseText string
if(window.DOMParser) {
parser = new DOMParser();
xml = parser.parseFromString(xhr.responseText,"text/xml");
} else {
// Internet Explorer
xml = new ActiveXObject("Microsoft.XMLDOM");
xml.async = "false";
xml.loadXML(xhr.responseText);
}
}
console.log('complete: ' + process_xml(xhr.responseText));
}
$('#uploadForm').ajaxForm(options);
})();
</script>
Thanks in advance.
IE is notoriously fussy when it comes to accepting XML and parsing it. Try something like this:
function process_xml(xml) {
var type = $(xml).find('type').text() ;
$('#type').html(type) ;
// Find other elements and add them to your document
}
$(function() {
$('#uploadForm').ajaxForm({
dataType: "xml", // 'xml' passes it through the browser's xml parser
success: function(xml,status) {
// The SUCCESS EVENT means that the xml document
// came down from the server AND got parsed successfully
// using the browser's own xml parsing caps.
process_xml(xml);
// Everything goes wrong for Internet Explorer
// when the mime-type isn't explicitly text/xml.
// If you are missing the text/xml header
// apparently the xml parse fails,
// and in IE you don't get to execute this function AT ALL.
},
complete: function(xhr,status){
if(status == 'parsererror'){
xmlDoc = null;
// Create the XML document from the responseText string
if(window.DOMParser) {
parser = new DOMParser();
xml = parser.parseFromString(xhr.responseText,"text/xml");
} else {
// Internet Explorer
xml = new ActiveXObject("Microsoft.XMLDOM");
xml.async = "false";
xml.loadXML(xhr.responseText);
}
process_xml(xml);
}
},
error: function(xhr,status,error)
{
alert('ERROR: ' + status) ;
alert(xhr.responseText) ;
}
});
});
Also,use alert() throughout debugging to provide feedback on what information is being passed through at all times.
EDIT
The crucial thing is ensure your XML file is 'well-formed', i.e. it must not contain any syntax errors. You need to begin the XML file with:
<?xml version="1.0"?>
It's not so much a server issue because, the errors come from your browser (i.e. Internet Explorer) because it thinks the XML is malformed. The error comes from your browser and indicates that your XML is malformed. You can manually set what headers you want returned with these $.ajax() settings:
dataType: ($.browser.msie) ? "text" : "xml",
accepts: {
xml: "text/xml",
text: "text/xml"
}
Or another way to do the same thing is to ask for a particular header:
headers: {Accept: "text/xml"},
The difference between the content-types application/xml and text/xml are minor (it's based on each XML's charset), but if you want to know you can read this post.
Perhaps give this a try? I use this with a google maps store locator. I notice $.parseXML actually does this internally, but its within a try/catch, and its saying your data is null (which is weird?)
var xml;
if (typeof data == "string") {
xml = new ActiveXObject("Microsoft.XMLDOM");
xml.async = false;
xml.loadXML(data);
} else {
xml = data;
}
From jQuery:
// Cross-browser xml parsing
parseXML: function( data ) {
var xml, tmp;
try {
if ( window.DOMParser ) { // Standard
tmp = new DOMParser();
xml = tmp.parseFromString( data , "text/xml" );
} else { // IE
xml = new ActiveXObject( "Microsoft.XMLDOM" );
xml.async = "false";
xml.loadXML( data );
}
} catch( e ) {
xml = undefined;
}
if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
jQuery.error( "Invalid XML: " + data );
}
return xml;
},
I have used that plugin before. If I recall this right it is using an iframe to fetch the information and then it is reading the content in the iframe. The content is stored in the property responseText. But IE may have stricter rules than other browsers. Have you tried printing out the value of data.responseText?
If the value is not a XML string. I hate to say it but the API isn't made for Javascript. What I've learned is that JSONP with manipulating the script tags is the best way to do cross domain XHR. Which I don't think this plugin does.
demo: http://bit.ly/HondPC
js code:
$(function() {
$('#uploadForm').ajaxForm({
dataType : 'xml', // OR $('#uploadResponseType option:selected').val()
beforeSubmit : function(a, f, o) {
$('#uploadOutput').html('Submitting...');
},
success : function(data) {
var original = $(data).find('links').find('original').text();
$('#uploadOutput').html('<img src="' + original + '" alt="" />');
}
});
});
php code:
<?
$api_key = "****************************";
$file = getcwd() . '/' . basename( $_FILES['image']['name'] );
move_uploaded_file($_FILES['image']['tmp_name'], $file);
$handle = fopen($file, "r");
$data = fread($handle, filesize($file));
$pvars = array('image' => base64_encode($data), 'key' => $api_key);
$post = http_build_query($pvars);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://api.imgur.com/2/upload.xml');
curl_setopt($curl, CURLOPT_TIMEOUT, 30);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/x-www-form-urlencoded"));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$xml = curl_exec($curl);
curl_close ($curl);
unlink($file);
header('Content-type: text/xml');
echo $xml;
?>
I trid to use an upload plugin for jQuery.
http://valums.com/ajax-upload/
When I set the returning respond type to json, firefox will popup a dialog asking how I like to handle the returning json object.
People have asked the same question at the upload script's author's page but no answer so far. Hopefully javascript guys here can figure out how we can handle this.
Thanks.
<script type= "text/javascript">
/*<![CDATA[*/
$(document).ready(function(){
/* example 1 */
var button = $('#button1'), interval;
new AjaxUpload(button, {
//action: 'upload-test.php', // I disabled uploads in this example for security reasons
action: '/posts/upload_images/',
name: 'myfile',
responseType: 'json',
onSubmit : function(file, ext){
// change button text, when user selects file
button.text('Uploading');
// If you want to allow uploading only 1 file at time,
// you can disable upload button
this.disable();
// Uploding -> Uploading. -> Uploading...
interval = window.setInterval(function(){
var text = button.text();
if (text.length < 13){
button.text(text + '.');
} else {
button.text('Uploading');
}
}, 200);
},
onComplete: function(file, response){
var json = response;
alert(json);
button.text('Upload');
window.clearInterval(interval);
// enable upload button
this.enable();
// add file to the list
// $('<li></li>').appendTo('#example1 .files').text(json.response_text);
$('<li></li>').appendTo('#example1 .files').text(file);
}
});
});
/*]]>*/
</script>
http://api.jquery.com/jQuery.parseJSON/
var obj = jQuery.parseJSON('{"name":"John"}');
alert( obj.name === "John" );
This jQuery plugin makes it simple to convert to and from JSON: http://code.google.com/p/jquery-json/
Also, you might be interested in this comment on the blog post you referenced:
Sorry to spam your blog post (which is great), but I thought I’d mention that I found the problem:
For whatever reason, the response always has <pre> tags around the entire response when the response is of type plain/text. That was causing the eval() call to fail. My current solution was just to strip those tags off before the eval() call and now everything works. Not a great solution but at least I can keep working for now.
I was looking for a solution for the same script and stumbled upon this page. I didn't found a solution online so here's how I fixed it:
# upload-file.php:
replace
echo "success".$cc;
with
echo json_encode(array(
status' => 'success',
'id' => $picid,
'image' => $imgurl
));
# front end:
replace
var bb=response.substr(0,7)
var idd=response.replace('success',' ');
var idb =idd.replace(/^\s*|\s*$/g,'');
if(bb==="success")
{
$('<span></span>').appendTo('#files').html('<img src="images/'+file+'" alt="" width="120" height="120" style="margin:5px;" />').addClass('success');
}
else
{
$('<span></span>').appendTo('#files').text(file).addClass('error');
}
with
var what = jQuery.parseJSON(response);
if(what.status == 'success')
{
$('<span id='+what.id+'></span>').appendTo('#files').html('<img src="'+what.image+'" alt="" width="120" height="120" style="margin:5px;" /><br>Delete').addClass('success');
}
else
{
$('<span></span>').appendTo('#files').text(response).addClass('error');
}
And to actually answer this question.
jQuery.parseJSON(response);
does..
This may be it, I don't know because I know nothing about that plugin, but you may need to take a look at the response type you are setting on the server-side of things; you should set the HTTP response to have a content/MIME type of something like "text/plain", "text/javascript" or "application/javascript" - see if that fixes your problem.