Re-render Django view based on jQuery-initiated AJAX POST request - html

The problem I face has to do with re-rendering a Django view based on a context that is updated by an AJAX post request that is initiated by jQuery. The reason why I need an AJAX request is because I need to modify the page UI without refreshing the page, which is critical to what I want to build.
So far, I am able to trigger the AJAX post request to the URL of the same page where the update is supposed to occur, and the Django view.py adequately registers that it has been called. However, although I can reproduce the ability to update the Django view's context, the view does not seem to re-render an updated HTML based on the updated context.
The thread at How to re-render django template code on AJAX call seems to describe exactly my problem. The top-voted solution of this thread is to have a conditional that is only triggered in case of an AJAX call that renders only a partial template (not the full HTML page) - a partial template that corresponds to the component to be updated. This is what's being reproduced in the code snippets below, but the HTML does not change based on the updated context.
Attached are the relevant code snippets for a simple attempt where the page displays <h1>2<h1/> by default and is meant to be updated to 5 when we click anywhere on the window. Clicking anywhere on the window triggers the AJAX call, but the page is not updated with <h1>5<h1/>.
view.py
def index(request):
context = {"num": 2}
if (request.method == "POST"):
print("View hit due to AJAX call!") # // THIS CAN BE TRIGGERED ADEQUATELY!
context["num"] = 5
return render(request, 'num.html', context)
return render(request, 'override.html', context)
override.html
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="{% static 'js/num.js' %}" defer></script>
<title>Title</title>
</head>
<body class="">
<div class="">
{% include 'num.html' %}
</div>
</body>
</html>
num.html
<h1>{{ num }}</h1>
num.js
var postUrl = "http://localhost:8000/";
function getCSRFToken() {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
if (cookie.substring(0, 10) == ('csrftoken' + '=')) {
cookieValue = decodeURIComponent(cookie.substring(10));
break;
}
}
}
return cookieValue;
}
$('html').click(function(){
values = [1, 2];
var jsonText = JSON.stringify(values);
$.ajax({
url: postUrl,
headers: { "X-CSRFToken": getCSRFToken(), "X-Requested-With": "XMLHttpRequest" },
type: 'POST',
data: jsonText, // note the data, jsonText, does not really matter. The Django context gets updated to 5 instead of 2.
traditional: true,
dataType: 'html',
success: function(result){
console.log("AJAX successful") // THIS CAN BE TRIGGERED ADEQUATELY!
}
});
});

If this part of code
success: function(result){
console.log(result)
}
prints the content of num.html you can change the num.html to get h1 id as
num.hml
<h1 id="numberToChange">{{ num }}</h1>
and in your num.js
$('html').click(function(){
values = [1, 2];
var jsonText = JSON.stringify(values);
$.ajax({
url: postUrl,
headers: { "X-CSRFToken": getCSRFToken(), "X-Requested-With": "XMLHttpRequest" },
type: 'POST',
data: jsonText, // note the data, jsonText, does not really matter. The Django context gets updated to 5 instead of 2.
traditional: true,
dataType: 'html',
success: function(result){
document.getElementById("numberToChange").innerHTML = result}
});
});

Related

Can't identify elements after ajax insert

There is a data in Django DB, when html page loaded it sends request to db and create html block in Django template, and at last it insert to html by id. This part works, checkboxes creates and all is good, but there is no elements if I try to find them by id after ajax insert.
How to to get access them?
html:
<div id="fill-statuses" status-table-url="{% url 'ajax_status_data' %}"></div>
Django template:
{% for status in statuses %}
<label class="toggle">
<input class="toggle__input" type="checkbox" id="{{ status.status_new }}_status_check_box">
<span class="toggle__label">
<span class="toggle__text">{{ status.status_new }}</span>
</span>
</label>
{% endfor %}
view.py:
def fill_status_check_boxes(request):
statuses = TaskStatus.objects.values('status_new').distinct
return render(request, 'persons/statuses_for_filter.html', {'statuses': statuses})
And now js block, with comments:
function fill_status_check_boxes() {
const url = $("#fill-statuses").attr('status-table-url')
$.ajax({
url: url,
success: function (data) {
$('#fill-statuses').html(data)
},
complete: function () {
console.log(document.querySelectorAll("[id*='status_check_box']")) //return array with elements, that's why I thought that all works, when tested it
}
})
console.log(document.querySelectorAll("[id*='status_check_box']")) //but here return empty array []
}
fill_status_check_boxes()
console.log(document.querySelectorAll("[id*='status_check_box']")) //and here also return empty array []
$.ajax() is executed asynchronously
So that's why your console.log inside the complete callback display what you're expecting, instead of the one after the ajax call.
You can create a new function to call on complete :
function fill_status_check_boxes() {
const url = $("#fill-statuses").attr('status-table-url')
$.ajax({
url: url,
success: function (data) {
$('#fill-statuses').html(data)
},
complete: handleComplete
})
}
fill_status_check_boxes()
function handleComplete() {
// Do some stuffs
console.log(document.querySelectorAll("[id*='status_check_box']"))
}

Formatting entity in json format does'nt show in view

This is the view, the success function should make changes in the <p id="mondiv"></p>tags.
<input type="button" value="Refuser" class="refuser" id="{{ demande.id }}">
<p id="mondiv"></p>
<script>
$(".refuser").click(function () {
$.ajax({
url: '{{ path('verifier_demandes') }}',
type: 'POST',
data: {'id_demande': this.id},
dataType: 'json',
success: function (data) {
$.each(data,function (i,e) {
$('#mondiv').append('<ul>'
+'<li>'+e.id+'</li>'
+'<li>'+e.etat+'</li>'
+'<li>'+e.user.nom+'</li>'
+'<li>'+e.user.prenom+'</li>'
+'<li>'+e.user.username+'</li>'
+'</ul>');
})
},
error: function(data) {
alert('error');
}
})
}
);
This is the controller, the entity gets deleted like intended but since then i can't change my view element ( the success function )
if($request->isXmlHttpRequest())
{
if ($request->get('id_demande')) {
$id_gerant = $request->get('id_demande');
$gerant = new Gerant();
$gerant = $em->getRepository("GestionBoutiquesBundle:Gerant")->findOneBy(array('id' => $id_gerant));
$em->remove($gerant);
$em->flush();
$demandes = new Gerant();
$demandes=$em->getRepository('GestionBoutiquesBundle:Gerant')->findBy(array('etat'=>false));
$ser= new Serializer(array(new ObjectNormalizer()));
$data=$ser->normalize($demandes);
return new JsonResponse($data);
}
}
I have looked from both sides, the controller sending back the Json response, and from the view, but couldn't find any result.
EDIT: knowing that the $demandes i'm trying to send back with Json is an array of users, each user has an id, etat, nom, prenom, username..
You made a POST request so you should be able to access to the post data as follow:
$id_gerant = $request->request->get('id_demande');
if($id_gerant) {
....
instead of:
if ($request->get('id_demande')) {
$id_gerant = $request->get('id_demande');
....
As described here in the doc Symfony Request Object
Hope this help

Constant POST request to different server from HTML

I want to create a HTML page which offers a button (link, some other clickable element, etc.) which, when pressed, sends a specific constant POST request to a specific constant server. The value I need to post is a specific constant JSON-encoded value ({"key":"value"}), so for HTTP it is just a very short constant string.
The value and the URL I have to use are constant. In order to make something happen, I have to send exactly this constant POST request. There is no need to parameterize this request or to "set a value" or similar. Also, I have no parameter name or similar. I must not send a parameter list with a parameter whose value is the JSON-encoded value, but I must send the JSON-encoded value by itself. The complete POST request can look like this:
POST /post/path/to/action HTTP/1.1
Host: the.specific.server
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
{"key":"value"}
(NOT parameter={"key":"value"} or similar as body!)
The server is not under my authority but a service I want to use.
With pure shell means I can do this very simply using curl:
curl http://the.specific.server/post/path/to/action -d '{"key":"value"}'
I imagined something like
<button url="http://the.specific.server/post/path/to/action"
value="{%22key%22:%22value%22}">visible text</button>
but I found nothing appropriate.
Based on questions like this or this or this I tried various approaches like this one:
<form method="POST" action="http://the.specific.server/post/path/to/action">
<input type="text" id="key" key="value">value</input>
<button type="submit" value="{%22key%22:%22value%22}">visible text</button>
</form>
With or without the input field, the button, with other arguments, other values, etc. but nothing finally sent anything useful to the server when pressed. At best I got something which was also transmitting a parameter name (thus the payload was not just the Json-encoded value).
I guess I'm just missing something basic in this :-}
There is no way in HTML to generate JSON from forms. You need here to implement this using an AJAX request.
Using jQuery it could be something like that:
$.ajax({
type: 'POST',
url: 'http://the.specific.server/post/path/to/action',
data: '{"key":"value"}',
success: function() {
// Successful response received here
},
dataType: 'json',
contentType : 'application/json'
});
This will be trigger when clicking on a button or a link, as described below:
$('#myButtonId').click(function() {
$.ajax({
(...)
});
});
This can be put for example in a script in your page after including jQuery library, as described below:
<html>
<head>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript">
// Waiting for the DOM to be loaded
$(document).ready(function() {
$('#myButtonId').click(function() {
// When button is clicked
$.ajax({
(...)
});
});
});
</script>
<body>
<button id="myButtonId">CLICK ME</button>
</body>
</head>
Edited
Here is the way to send an HTTP request using raw JavaScript API: http://www.quirksmode.org/js/xmlhttp.html.
I adapted this code to work for your use case:
function sendRequest(url, callback, postData, contentType) {
var req = createXMLHTTPObject();
if (!req) return;
var method = (postData) ? "POST" : "GET";
req.open(method,url,true);
req.setRequestHeader('User-Agent','XMLHTTP/1.0');
if (postData) {
if (contentType) {
req.setRequestHeader('Content-type', contentType);
} else {
req.setRequestHeader('Content-type',
'application/x-www-form-urlencoded');
}
}
req.onreadystatechange = function () {
if (req.readyState != 4) return;
if (req.status != 200 && req.status != 304) {
return;
}
callback(req);
}
if (req.readyState == 4) return;
req.send(postData);
}
var XMLHttpFactories = [
function () {return new XMLHttpRequest()},
function () {return new ActiveXObject("Msxml2.XMLHTTP")},
function () {return new ActiveXObject("Msxml3.XMLHTTP")},
function () {return new ActiveXObject("Microsoft.XMLHTTP")}
];
function createXMLHTTPObject() {
var xmlhttp = false;
for (var i=0;i<XMLHttpFactories.length;i++) {
try {
xmlhttp = XMLHttpFactories[i]();
} catch (e) {
continue;
}
break;
}
return xmlhttp;
}
To execute your request, simply use the function sendRequest:
sendRequest(
'http://the.specific.server/post/path/to/action',
function() {
// called when the response is received from server
},
'{"key":"value"}',
'application/json');
Hope it helps you,
Thierry
A simple, customisable an no dependencies solution based on : https://gist.github.com/Xeoncross/7663273
May works on IE 5.5+, Firefox, Opera, Chrome, Safari.
<html>
<body>
<button id="myButtonId" onclick='post("http://the.specific.server/post/path/to/action", "{\"key\":\"value\"}");'>CLICK ME</button>
</body>
<script>
function post(url, data, callback) {
try {
var req = new(this.XMLHttpRequest || ActiveXObject)('MSXML2.XMLHTTP.3.0');
req.open('POST', url, 1);
req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
req.send(data)
} catch (e) {
window.console && console.log(e);
}
}
</script>
</html>
You are looking for FORM encoding algorithm which enables form data to be transmitted as json.
Have a look at W3C HTML JSON form submission. It is not active and not likely to be maintained.
So, you are better off using the above JS or Jquery solution or use a server side forwarding. My suggestion is to use jquery as most websites point to google cdn these days and jquery is mostly browser cached. With below code, you neatly fire a POST request without worrying about underlying browser variants.
$.ajax({
type: 'POST',
url: 'http://the.specific.server/post/path/to/action',
data: '{"key":"value"}',
success: function() {
// Successful response received here
},
dataType: 'json',
contentType : 'application/json'
});
Try this suggestion using JQuery methods and Ajax:
$(document).ready(function(){
$("#myForm").submit(function(){
$.ajax({type:"POST",
data: $(this).serializeObject(),
url:"http://the.specific.server/post/path/to/action",
contentType: "application/json; charset=UTF-8",
success: function(data){
// ... OK
},
error: function(){
// ... An error occured
}
});
return false;
});
});
Note : serializeObject method converts form elements to a JSON string.
I now went for a simplistic solution (because that's what I wanted) I found myself by searching for more answers. It seems there is no way around using JS for this task.
<button onClick="postCommand('mypath', 'mykey', 'myvalue')">Click</button>
<script>
function postCommand(path, key, value) {
var client = new XMLHttpRequest();
var url = "http://the.specific.server/" + path;
client.open("POST", url, true);
client.send("{\"" + key + "\":\"" + value + "\"}");
}
</script>
This is in general #aprovent's answer, so I accepted his and granted him the bounty.

How to get HTML content inside an iFrame to an Action and save it in DB?

I'm having a school timetable manually created. The number of textboxes are 33. I want to store it in db. But what if I store its innerHtml content in Db? Since the students can also view the timetable, but fetching that much data may decrease performance.
I'm trying to get the data using Ajax, but nothing happens. Not even an error.
I'm working on Java with Struts Framework and the fields are inside an iFrame element.
I don't know what to write in execute method to get the html content.
Ajax Code :
<script type="text/javascript">
var jarray=[];
var jsonTT={};
var jsonTTData="";
function GenerateTableJson(){
jsonTTData="";
jsonTTData=$("#bdyTimeTableData").html();
jsonTT["timeTable"]=escape(jsonTTData.trim());
$("#contentTT").val(jsonTT);
console.log(jsonTT);
var postdata ={};
postdata = {
"FinalSave":[{
"timeTable":"TT",
"department":$("#departmentid").val(),
"semester":$("#semesterid").val(),
"division":$("#divisionid").val()
}]
};
postdata = JSON.stringify(postdata);
$.ajax({
url: "SaveNPrintTT.action",
cache:false,
contentType : 'application/json',
type : 'POST',
async : true,
data:postdata,
success:function(res){
$.ajax({
url: url,
cache:false,
method:"POST",
dataType : 'json',
success:function(res){
}
});
}
});
return true;
}
function PrintPreview() {
var toPrint = document.getElementById('bdyTimeTableData');
var popupWin = window.open('TimeTable', '_blank', 'resizable=yes,scrollbars=yes,status=yes');
popupWin.document.open();
popupWin.document.write('<html><title>::Print Preview::</title><link rel="stylesheet" type="text/css" href="Print.css" media="screen"/></head><body onload="window.print()""">')
popupWin.document.write(toPrint.innerHTML);
popupWin.document.write('</html>');
popupWin.document.close();
window.PrintPreview =PrintPreview;
}
</script>
My JSP code.
Only Textboxes with values.
But for save button, I'm calling Action Class name - saveTT
I need the content in Action to save it in Db. OR Do i write an insert query, inserting 33 values in db?

How to fetch a specific div id from an html file through ajax

I have two html files called index.html & video.html
video.html holds coding like:
<div id="video">
<iframe src="http://www.youtube.com/embed/tJFUqjsBGU4?html5=1" width=500 height=500></iframe>
</div>
I want the above mentioned code to be crawled from video.html page from index.html
I can't use any back-end coding like php or .net
Is there any way to do using Ajax?
Try this...
$.ajax({
url: 'video.html',
success: function(data) {
mitem=$(data).filter('#video');
$(selector).html(mitem); //then put the video element into an html selector that is on your page.
}
});
For sure,send an ajax call.
$.ajax({
url: 'video.html',
success: function(data) {
data=$(data).find('div#video');
//do something
}
});
Yep, this is a perfect use case for ajax. When you make the $.ajax() request to your video.html page, you can then treat the response similar to the way you'd treat the existing DOM.
For example, you'd start the request by specifying the URI in the the following way:
$.ajax({
url: 'video.html'
})
You want to make sure that request succeeds. Luckily jQuery will handle this for you with the .done callback:
$.ajax({
url: "video.html",
}).done(function ( data ) {});
Now it's just a matter of using your data object in a way similar to the way you'd use any other jQuery object. I'd recommend the .find() method.
$.ajax({
url: "video.html",
}).done(function ( data ) {
$(data).find('#video'));
}
});
Since you mentioned crawl, I assume there is the possibility of multiple pages. The following loads pages from an array of urls, and stores the successful loads into results. It decrements remainingUrls (which could be useful for updating a progressbar) on each load (complete is called after success or error), and can call a method after all pages have been processed (!remainingUrls).
If this is overkill, just use the $.ajax part and replace myUrls[i] with video.html. I sepecify the type only because I ran into a case where another script changed the default type of ajax to POST. If you're loading dynamic pages like php or aspx, then the cache property might also be helpful if you're going to call this multiple times per session.
var myUrls = ['video1.html', 'video2.html', 'fail.html'],
results = [],
remainingUrls;
$(document).ready(function () {
remainingUrls = myUrls.length;
for (var i = 0, il = myUrls.length; i < il; i++) {
$.ajax({
url: myUrls[i],
type: 'get', // somebody might override ajax defaults
cache: 'false', // only if you're getting dynamic pages
success: function (data) {
console.log('success');
results.push(data);
},
error: function () {
console.log('fail');
},
complete: function() {
remainingUrls--;
if (!remainingUrls) {
// handle completed crawl
console.log('done');
}
}
});
}
});
not tested, but should be something similair to this: https://stackoverflow.com/a/3535356/1059828
var xhr= new XMLHttpRequest();
xhr.open('GET', 'index.html', true);
xhr.onreadystatechange= function() {
if (this.readyState!==4) return;
if (this.status!==200) return; // or whatever error handling you want
document.getElementsByTagName('html').innerHTML= this.responseText;
};
xhr.send();