I have a function in python which will return one of many Image URLs. I would like to implement a button on a webpage made with django which will change the image's source to the returned value. The issue I've run into is that django template tags are only accessible when the page is rendered, as explained here. Since the real code cannot be recreated in javascript, is there a workaround to get access to the python function's return data every time the button is pressed?
Here is some code to clarify my question:
class Foo(models.Model):
def get_image_url():
if(random.randint(0,1)):
return 'http://img1.jpg'
else:
return 'http://img2.jpg'
This is how I would want it to behave in javascript, if it were possible.
function updateImage(){
document.getElementById("testImage").src="{{ foo.get_image_url }}";
}
Thanks.
Sounds like you have to use AJAX for this. You can define a Django view which returns a JSON message with something like:
{
status: "ok",
url: "img1.jpg"
}
So in your code, you can define an event handler (in JavaScript) with something like this:
// Attach a listener to a button for a click event,
document.getElementById("testImageButton").addEventListener("click", function() {
var xhr = new XMLHttpRequest();
// This URL returns the above JSON.
xhr.open("GET", "/images/random");
xhr.onloadend = function() {
// Should have error handling in case response does not return correctly.
var imageResult = JSON.parse(xhr.response);
if(imageResult['status'] == 'ok') {
// update the image src
document.getElementById("testImage").setAttribute("src", imageResult['url']);
}
}
xhr.send()
})
So the only "dynamic function part" is whatever is inside your Django view function.
Related
I have a Javascript function to send a PUT request to my Flask backend specifying a project with a certain id to be deleted, this function works as expected in sending a PUT request when it is set to run onclick for an HTML element. However, when I try adding another function to the onclick to refresh the window (to refresh the list of projects to reflect the deletion), the function will not send a PUT request.
What I don't understand is, why if my function works normally, does it then not work when I run another function after it? The function is called as can be seen by the confirm prompt, but doesn't send a PUT request (it does call the refresh function afterwards though).
I tried using a single function onclick which then calls both functions, and both functions in onclick (functionA(); functionB();) but neither of these approaches works, unless I solely call one function the PUT request will not be sent.
My Javascript functions are:
function refreshWindow() {
window.location.reload();
}
function deleteProject(pid) { // Function to send a put request to delete the project with ProjectID pid
if (confirm("Are you sure you want to delete this project?")) {
const xhttp = new XMLHttpRequest();
var data = {};
data.id = pid;
data.action = "delete";
var json = JSON.stringify(data);
xhttp.open("PUT", currenturl, true);
xhttp.setRequestHeader('Content-type','application/json; charset=utf-8');
xhttp.send(json);
}
}
function deleteProjectRefresh(pid) {
deleteProject(pid);
refreshWindow();
}
and the relevant HTML element is: (the {{ project[0][0] }} part just inserts the ID into the HTML - Jinja template)
<img onclick="deleteProjectRefresh({{ project[0][0] }})" title="Delete" src="../static/img/Delete Button.png"></td>
If you call deleteProjectRefresh then javascript will execute deleteProject and refreshWindow simultaneously. So your browser will refresh before it has the chance to run the Ajax request.
You can fix this by using a callback before calling refreshWindow
function refreshWindow() {
window.location.reload();
}
function deleteProject(pid) { // Function to send a put request to delete the project with ProjectID pid
if (confirm("Are you sure you want to delete this project?")) {
const xhttp = new XMLHttpRequest();
var data = {};
data.id = pid;
data.action = "delete";
var json = JSON.stringify(data);
xhttp.open("PUT", currenturl, true);
xhttp.setRequestHeader('Content-type','application/json; charset=utf-8');
// Add a call back for the onreadystatechange event
xhttp.onreadystatechange = function() {
if (xhttp.readyState === 4) {
refreshWindow(); //MOVED TO HERE
}
}
xhttp.send(json);
}
}
function deleteProjectRefresh(pid) {
deleteProject(pid);
//refreshWindow(); MOVE THIS
}
The refreshWindow() function is called immediately after you fire the HTTP PUT, so it executes before the PUT returns anything, I am not sure if that is relevant.
Personally, I don't use onClick() at all, I always use an event to bind the code to an action, thereby separating the code and presentation.
I have a website where I need to update a status.
Like for a flight, you are departing, cruise or landed.
I want to be able to refresh the status without having my viewers to have and reload the whole page. I know there is a way to do it with AJAX and jQuery, but I don't have any understanding of how that works. I also don't want them to have and click a button.
If anybody knows how that would be done I much appreciate it!
This is typically achieved with a technique called AJAX. This technique loads data asynchronously (in the background) so it can update your content without needing to reload the page.
The easiest way to implement AJAX is with the jQuery load() method. This method provides a simple way to load data asynchronous from a web server and place the returned HTML into the selected element. The basic syntax of this method is: $(selector).load(url, data, complete); where the arguments are:
selector the existing HTML element you want to load the data into
url a string containing the URL to which the request is sent
data (optional) a plain object or string that is sent to the server with the request
complete (optional) a callback function that is executed when the request completes
The required URL parameter specifies the URL of the file you want to load.
The optional data parameter allows you to specify data (i.e. key/value pairs) that is sent to the web server along with the request. The optional complete parameter can be used to reference a callback function. The callback is fired once for each selected element.
A visualisation:
A simple example of using load(), where we load data dynamically when a button is pressed:
DEMO
// no need to specify document ready
$(function(){
// optional: don't cache ajax to force the content to be fresh
$.ajaxSetup ({
cache: false
});
// specify loading spinner
var spinner = "<img src='http://i.imgur.com/pKopwXp.gif' alt='loading...' />";
// specify the server/url you want to load data from
var url = "http://fiddle.jshell.net/dvb0wpLs/show/";
// on click, load the data dynamically into the #result div
$("#loadbasic").click(function(){
$("#result").html(spinner).load(url);
});
});
If you don't want to use the jQuery library, you can also use plain Javascript. Loading content is slightly more difficult that way. Here is an example of how to do it with javascript only.
To learn more about AJAX, you can take a look at https://www.w3schools.com/xml/ajax_intro.asp
Suppose you want to display some live feed content (say livefeed.txt) on you web page without any page refresh then the following simplified example is for you.
In the below html file, the live data gets updated on the div element of id "liveData"
index.html
<!DOCTYPE html>
<html>
<head>
<title>Live Update</title>
<meta charset="UTF-8">
<script type="text/javascript" src="autoUpdate.js"></script>
</head>
<div id="liveData">
<p>Loading Data...</p>
</div>
</body>
</html>
Below autoUpdate.js reads the live data using XMLHttpRequest object and updates the html div element on every 1 second. I have given comments on most part of the code for better understanding.
autoUpdate.js
window.addEventListener('load', function()
{
var xhr = null;
getXmlHttpRequestObject = function()
{
if(!xhr)
{
// Create a new XMLHttpRequest object
xhr = new XMLHttpRequest();
}
return xhr;
};
updateLiveData = function()
{
var now = new Date();
// Date string is appended as a query with live data
// for not to use the cached version
var url = 'livefeed.txt?' + now.getTime();
xhr = getXmlHttpRequestObject();
xhr.onreadystatechange = evenHandler;
// asynchronous requests
xhr.open("GET", url, true);
// Send the request over the network
xhr.send(null);
};
updateLiveData();
function evenHandler()
{
// Check response is ready or not
if(xhr.readyState == 4 && xhr.status == 200)
{
dataDiv = document.getElementById('liveData');
// Set current data text
dataDiv.innerHTML = xhr.responseText;
// Update the live data every 1 sec
setTimeout(updateLiveData(), 1000);
}
}
});
For testing purpose: Just write some thing in the livefeed.txt - You will get updated the same in index.html without any refresh.
livefeed.txt
Hello
World
blah..
blah..
Note: You need to run the above code on the web server (ex: http://localhost:1234/index.html) not as a client html file (ex: file:///C:/index.html).
You can read about jQuery Ajax from official jQuery Site:
https://api.jquery.com/jQuery.ajax/
If you don't want to use any click event then you can set timer for periodically update.
Below code may be help you just example.
function update() {
$.get("response.php", function(data) {
$("#some_div").html(data);
window.setTimeout(update, 10000);
});
}
Above function will call after every 10 seconds and get content from response.php and update in #some_div.
If you want to know how ajax works, it is not a good way to use jQuery directly. I support to learn the native way to send a ajax request to the server, see something about XMLHttpRequest:
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://some.com");
xhr.onreadystatechange = function () {}; // do something here...
xhr.send();
I'm creating a simple JavaScript code to intercept any AJAX request with the idea of add an extra param that I need to read in the server side (Java). Until now I have this code that I have tested with different kind of request, with and without jquery as well, works fine:
(function(open) {
XMLHttpRequest.prototype.send = function() {
console.log('Start a new AJAX request');
var myExtraParam = 'ABC123'; // value that I need to send, but it's dynamically, it will come from a function
open.apply(this);
};
})(XMLHttpRequest.prototype.send);
What I have been looking is the way to attach an extra parameter, on this scenario, the variable "myExtraParam" when I call the apply method.
I'm using plain JavaScript
EDIT:
As param, I'm asuming a value that I can read in the server, like when you do: myurl?myExtraParam=ABC123
Setting a parameter seems like a lot of work dealing with querystring or appending it to the request body. Safer thing seems to be using a header.
(function() {
var orgSend = window.XMLHttpRequest.prototype.send;
window.XMLHttpRequest.prototype.send = function() {
this.setRequestHeader("foo", "bar")
return orgSend.apply(this, [].slice.call(arguments));
};
})();
I'm uploading a file in an iframe (with name and id=upload_target) to some server. As a response it creates a callback json style :
'result':'true'
So I'm trying the following. On onload action of my IFrame I've added an event listener, which should run function grabbing data :
function fileUploadFunction(){
(...)
$("#upload_target").onload = uploadDone;
(...)
};
function uploadDone() {
alert("uploadDone");
var ret = frames['upload_target'].document.getElementsByTagName("body")[0].innerHTML;
var data = eval("("+ret+")");
if(data.result == 'true') {
alert("GREAT SUCCESS !!");
}
else {
alert("GREAT FAILURE :(");
}
}
But as a result I'm not getting anything at all. Should I return callback status in different form, or can it be solved differently ? Because even the first alert from uploadDone is not shown problem probably lies somewhere else.
Probably the reason nothing is happening is because of the funky way you have to detect an iFrame is loaded. Check the post jQuery .ready in a dynamically inserted iframe. I am assuming you are using jQuery.
We're using Prototype for all of our Ajax request handling and to keep things simple we simple render HTML content which is then assigned to the appropriate div using the following function:
function ajaxModify(controller, parameters, div_id)
{
var div = $(div_id);
var request = new Ajax.Request
(
controller,
{
method: "post",
parameters: parameters,
onSuccess: function(data) {
div.innerHTML = data.responseText;
},
onFailure: function() {
div.innerHTML = "Information Temporarily Unavailable";
}
}
);
}
However, I occasionally need to execute Javascript within the HTML response and this method appears incapable of doing that.
I'm trying to keep the list of functions for Ajax calls to a minimum for a number of reasons so if there is a way to modify the existing function without breaking everywhere that it is currently being used or a way to modify the HTML response that will cause any embedded javascript to execute that would great.
By way of note, I've already tried adding "evalJS : 'force'" to the function to see what it would do and it didn't help things any.
The parameter is:
evalScripts:true
Note that you should be using Ajax.Updater, not Ajax.Request
See: http://www.prototypejs.org/api/ajax/updater
Ajax.Request will only process JavaScript if the response headers are:
application/ecmascript,
application/javascript,
application/x-ecmascript,
application/x-javascript,
text/ecmascript, text/javascript,
text/x-ecmascript, or
text/x-javascript
Whereas Ajax.Updater will process JS is evalScripts:true is set. Ajax.Request is geared toward data transport, such as getting a JSON response.
Since you are updating HTML you should be using Ajax.Updater anyways.
Does setting evalScripts: true as an option help?
You should be able to do something like this:
div.innerHTML = "<div onclick='someOtherFunctionTocall();'>";
If you need to execute something at the same time as injecting the HTML, can you modify the signature of ajaxModify() by passing another parameter, which will be the javascript function you're going to execute (if it's not null - which let's you keep it optional, as you surely won't want to execute something on EVERY AJAX response).
Just execute a custom my_function() after the ajax response
div.innerHTML=...ajax response text...
my_function()
then execute any function inside the custom my_function()
function my_function() {
function_1()
...
}
Note that my_function() should be somewhere outside the div.innerHTML.
you need to use eval() function to run the javascript in Ajax repose
this can be use full to separate the script and run it
function PaseAjaxResponse(somemixedcode)
{
var source = somemixedcode;
var scripts = new Array();
while(source.indexOf("<script") > -1 || source.indexOf("</script") > -1) {
var s = source.indexOf("<script");
var s_e = source.indexOf(">", s);
var e = source.indexOf("</script", s);
var e_e = source.indexOf(">", e);
scripts.push(source.substring(s_e+1, e));
source = source.substring(0, s) + source.substring(e_e+1);
}
for(var x=0; x<scripts.length; x++) {
try {
eval(scripts[x]);
}
catch(ex) {
}
}
return source;
}
alliteratively for more information see this
http://www.yasha.co/Ajax/execute-javascript-on-Ajax-return/article-2.html