I have a site that makes an HTTP request for JSON data, then a callback function processes the data and displays it by creating a series of divs dynamically. What I want to do is to wait for that function to finish adding the divs to the page, then apply labels only to specific divs created by the previous code.
HTTP Request and Callback
function data(callback){
var url = //request url;
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState === 4) {
if (request.status === 200) {
document.body.className = 'ok';
//Parse returned string into an object, then pass the object to the callback function.
var data = JSON.parse(request.responseText);
callback(data);
} else {
document.body.className = 'error';
}
}
};
request.open("GET", url , true);
request.send(null);
}
function dataDisplay(data){
//outputs <div id="1064" class="displayed-data">
<p id="message1" class="hidden"></p>
}
data(dataDisplay);
The code above displays my data exactly how I want it to, but when I try to access the numbered ID of the divs I want to change, the function runs before the data is displayed on the page, causing a 'null' error because the data I am trying to change hasn't been added to the DOM yet.
Second Function to change original
function label(){
var message1 = document.createTextNode('//some label');
var displayedData = document.getElementById('1064').getElementById('message1');
displayedData.appendChild(message1);
document.getElementById('message1').classList.remove('hidden');
}
How do I get the second function to wait until the callback has completed before trying to access and change it? I tried a callback inside of a callback, something like: label(data(dataDisplay)); but it still threw the same errors, so I clearly did it wrong. Sorry, I am brand new to JavaScript and don't really know where to go from here.
Thanks for your help!
A pretty quick way of doing it correctly is with this inline function.
data(function(result) {
dataDisplay(result);
label();
});
Be aware that your data function itself completes very quickly - if you need something from its result, you will need to include it in its callback.
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.
How can I populate data into #Html.Textboxfor when we select value in #Html.DropdownListfor in ASP.NET MVC5 application. Which is the better way to populate the data in text box either by using scripting or is there any other way to do if so give me an example if possible.
This is how I would do it. Use JavaScript. You should make a script where all your ajax calls come from a single point of entry. It's easier to reuse, maintain and easier to debug. Keep in mind this code is just an outline, your going to have to clean it up. Don't hit the server as suggested and update your view model every time a dropdown list value changes. That is ridiculous. I'll give you my full approach to this situation. Just pull in the view model from an XMLHttpRequest how ever you like and filter the current data you have every time the dropdown list changes.
step 1: Make a request to your controller for the view model
//quick example
var xhr = new XMLHttpRequest();
xhr.open('GET', 'Controller/Methodname');
xhr.send(null);
step2: Get the ViewModel and store it in an object or variable or w/e you want
//handle the call
xhr.onreadystatechange = function () {
var DONE = 4; // readyState 4 means the request is done.
var OK = 200; // status 200 is a successful return.
if (xhr.readyState === DONE) {
if (xhr.status === OK)
...xhr.responseText // 'This is the returned text. so store it somewhere'
} else {
console.log('Error: ' + xhr.status); // An error occurred during the request.
}
}
};
step 3: Add an onChange event for the dropdown list.
onDropdownChange() {
// based on what is selected, filter you data and populate the textbox
document.getElementById("YourTextboxID").value = your value;
}
Try something like This.
function ondropdownchange(){
$.get("yourmethodurl", function(data, status){
$('#yourtextbox').val(data);
});
}
I am trying to solve this problem of mine: I am making two ajax calls on window.load, and it seems like second AJAX response rewrite first one before I function can proceed it or I am making something wrong... anyway I am not able to solve it without making calls synchronous and i don't really want to do that for obvious reasons.
So Here is my code (Javascript) To Create new XMLHttpRequest:
function createRequest(){
if(window.XMLHttpRequest)
return new XMLHttpRequest;
else
return new ActiveXObject("Microsoft.XMLHTTP");
}
My send request function (to sending them)
function sendRequest( url, callback){
request = createRequest();
if(typeof callback === 'function'){
request.onreadystatechange = callback();
}
request.open("GET", url, true);
request.send();
}
and finally my callback
function handleData(){
return function(){
if (request.readyState == 4 && request.status == 200) {
serverResponse = JSON.parse(request.responseText);
switch(Object.keys(serverResponse)[0]){
case "a": function1(serverResponse.a,"a"); break;
case "b": function2(serverResponse.b,"b"); break;
}
}
}
I am creating my calls like this:
window.onload = function () {
sendRequest('url' , handleData);
sendRequest('url2', handleData);
}
NOTICE: As you can see, this is simplified version of my code.
In a switch I am calling function1 and 2 these functions are really handling JSON response from server. I am making calls on two different urls on a same domain with different json response.
Also when I make only one call it works well(Both of them)... Problem only occurs when I am trying to make 2 in a row - And when i make two calls only second one is processed right. Thats why i am thinking that second overwrite first.
I tried to make two functions to handleData so there was handleData1() and handleData2() instead of single handleData() with switch so i call them like this:
window.onload = function () {
sendRequest('url' , handleData1);
sendRequest('url2', handleData2);
}
but i run into problem where second ajax response(always the second call) but again only second one succeed. And then i put console.log(request) in both of em, and i get only JSON for second function trying to be processed with second function.(nothing about first one) Sometimes is second function called more times like 4.
Btw handleData2 does not depend on data from handleData1.
If any more questions please do ask :) Thanks
request = createRequest();
creates a global variable. Every call to the function will override that variable, which is what you are experiencing.
Create a local variable and pass the value to the callback:
var request = createRequest();
if(typeof callback === 'function'){
request.onreadystatechange = callback(request);
}
// ...
function handleData(request) {
// ...
}
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.
I have three div elements, and I want to populate each element with its own content. I call the same AJAX (very generic) function each time, sending the name of the div id as a parameter:
//left-right rectangle content
var rl = getContent("rightLeft");
//bottom content
var br = getContent("bottomRectangle");
//top content
var rtr = getContent("rightTopRectangle");
If I do an alert(http.responseText) within the AJAX function, I get the correct html content from the remote page. (In fact, if I add an alert, it seems to "slow" the function down so that my content is returned properly each time I call it, but who wants alerts on their web page?).
But, without the alerts, the above calls will only properly process the last call. So, in the above sequence of calls, only the last div, where id="rightTopRectangle" will be filled with the html retrieved from the AJAX call. The previous two calls don't populate their divs with the AJAX retrieved html. If I shake up the order of the calls, it will always be the last AJAX call that works.
I get the feeling the problem has something to do with the asynchronous part, where the previous calls don't have enough time to process the request before the AJAX function is requested again and again.
Here's the AJAX function:
function getContent(element){
var url = "ajax/getcontent.php?cid="+element; //alert(url);
http.onreadystatechange=function(){
if (http.readyState==4 && http.status==200){ //alert(http.responseText);
var response = http.responseXML.documentElement;
callback(element,http.responseText);
}
}
http.open("GET",url,true);
http.send();
}
The function named "callback" (it works fine) looks like this:
function callback(e,c){
document.getElementById(e).innerHTML = "<div style=\"line-height:"+ document.getElementById(e).offsetHeight +"px;margin:0px auto 0px auto;text-align:center;\" >" + unescape(c) + "</div>";
}
UPDATE: This works now. I added one line to my getContent function:
function getContent(element){
var http = createRequestObject(); /*After Tej's answer, I took this line out
of the root of my script and placed it here, within the function, in order to
instantiate a new http object each time I call this function, so that they all
operate independently of one another*/
var url = "ajax/getcontent.php?cid="+element; //alert(url);
http.onreadystatechange=function(){
if (http.readyState==4 && http.status==200){
var response = http.responseXML.documentElement;
callback(element,http.responseText);
}
}
http.open("GET",url,true);
http.send();
}
You are re-using the same XmlHttpRequest for all of your ajax requests; this leads to the last request always winning because the others have been overwritten. You should instead create a new ajax request for each call.
http = CreateAjaxRequest();
http.onreadystatechange = function() { ... }
// etc
you should pass element parameter to your onreadystatechange function, try this,
req.onreadystatechange = function (el) {
return function() {
if (http.readyState==4 && http.status==200){ //alert(http.responseText);
var response = http.responseXML.documentElement;
callback(el,http.responseText);
}
};
}(element);