The Ajax request is being sent continuously and I am not sure why
placing return false in multiple areas of the code.
//when user clicks on create channel
document.querySelector('#add-channel').onclick = () => {
// pop up modal
modal1.style.display = "block";
// Initialize new request
document.querySelector('#form1').onsubmit = () => {
const request = new XMLHttpRequest();
const chatroom = document.querySelector('#chatroom').value;
const username = localStorage.getItem('name');
request.open('POST', '/add_chatroom');
// Callback function for when request completes
request.onload = () => {
// Extract JSON data from request
const data = JSON.parse(request.responseText);
// Update the result div
if (data.success) {
// get the data that was returned.
// add it back to the list
document.querySelector('#contacts').append(li);
}
else {
alert('chatroom already exists');
}
}
// add data to send to the server
const data = new FormData();
data.append('chatroom', chatroom);
data.append('username', username);
// Send request
request.send(data);
return false;
};
};
The post request won't stop everytime I click ok even though the event should only trigger when the form with id #form1 is submitted. It triggers even when i click ok for the alert.
I ended up changing the browser from Firefox to Microsoft edge to solve the onsubmit re-running issue, why this works is beyond my knowledge.
Related
I'm trying to make a pokedex for a school project, and am using JS for doing so. I found this api called pokeapi, and since it uses JSON, I thought of just getting the data in the page and returning a json of it, however when I try to use the method I created to do a request in a for loop, it doesn't seem to work, only working on the last element of the for loop:
let request = new XMLHttpRequest();
const getJSON = (link, action) => {
request.open("GET", link);
request.send();
request.onload = () => {
if (request.status === 200) {
let json = JSON.parse(request.response);
action(json);
} else {
console.log(`e:${request.status} ${request.statusText}`);
}
}
}
let counter = 1;
getJSON("https://pokeapi.co/api/v2/pokedex/1/", (json) => {
json.pokemon_entries.forEach((poke_entry) => {
getJSON(poke_entry.pokemon_species.url, (poke_sp) => {
console.log(poke_sp);
//console loggin poke_sp only shows one console log, the last member of `json.pokemon_entries`
})
});
});
This is because you have created a single XHR object.
Every time you make a request with it, you cancel the previous request.
Create a new XHR object (inside the getJSON function) for each request.
i.e. swap the order of
let request = new XMLHttpRequest();
and
const getJSON = (link, action) => {
I want to run some JS in a webpage so I can click elements that will take me to another webpage and do 2 things:
Get the destination URL.
Stop the redirection.
So far I read about adding an event listener to stop redirection:
window.addEventListener('beforeunload', function (e) {
// Cancel the event
e.preventDefault(); // If you prevent default behavior in Mozilla Firefox prompt will always be shown
// Chrome requires returnValue to be set
e.returnValue = '';
});
but there's always a popup and I cannot figure out the destination address.
Edit:
I was able to obtain the destination URL from the microservice by intercepting the XMLHttpRequests so the first problem is solved ... redirection is still an issue.
const xhrOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
if (method === "GET") {
const urlQuery = "some_discrimination_factor";
const urlPropertyName = "redirection_url";
if(url.endsWith(urlPropertyName)) {
this.onload = function(){
const response = JSON.parse(this.responseText);
if (response.hasOwnProperty(urlPropertyName)) {
console.log(response[urlPropertyName]);
}
};
}
}
xhrOpen.call(this, method, url, async, user, pass);
};
Here's the same thing but using DOM Level 2 Events:
let xhrListener; //use only to avoid multiple listeners error while debugging
const xhrOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
if (method === "GET") {
const urlQuery = "some_discrimination_factor";
const urlPropertyName = "redirection_url";
if(url.endsWith(urlPropertyName)) {
if (xhrListener) { //use only to avoid multiple listeners error while debugging
this.removeEventListener("readystatechange", xhrListener);
}
this.addEventListener("load", function nonAnonymWrap(e){
xhrListener = nonAnonymWrap;//use only to avoid multiple listeners error while debugging
const response = JSON.parse(this.responseText);
if (response.hasOwnProperty(urlPropertyName)) {
console.log(response[urlPropertyName]);
}
});
}
}
xhrOpen.call(this, method, url, async, user, pass);
};
CLICK ME
var dom = document.getElementById('#myEle1');
dom.addListener('click', function($e){
$e.preventDefault(); // stop <a> tag behavior
var url = dom.href; // the url you want
})
like this?
Ockham's razor:
Entities should not be multiplied without necessity.
Being new to JavaScript's rabbit hole I started going heavy on XMLHttpRequest but apparently something simpler was sufficient for my case:
//backup original function in case redirection is needed later
const windowOpen = window.open;
let isRedirectionEnabled = false;
window.open = function() {
//destination URL obtained without redirection
let targetUrl = arguments[0];
console.log(targetUrl);
if(isRedirectionEnabled) {
windowOpen.apply(this, arguments);
}
};
This question already has answers here:
How to replace the entire html webpage with ajax response?
(6 answers)
How to replace innerHTML of a div using jQuery?
(14 answers)
Closed 3 years ago.
In index.html, I'm getting a value stored in localStorage:
<script>
function checkChannel() {
if (localStorage.getItem('channel')) {
const channel = localStorage.getItem('channel');
const request = new XMLHttpRequest();
request.open('POST', '/convert');
// Add data to send with request
const data = new FormData();
data.append('channel', channel);
// Send request
request.send(data);
}
}
</script>
</head>
<body onload="checkChannel()">
.
.
.
This works fine. It is routed to the code below in application.py. The debugger hits the first line in convert() below, so I know it's getting there.
#app.route("/convert", methods=["POST"])
def convert():
channel = request.form.get("channel")
channel_messages = channels_dict[channel]
return render_template("channel.html", channel=channel, channel_messages=channel_messages)
However, channel.html is not being rendered. Instead, it stays on the same page. What am I doing wrong here? I can give more details if needed.
You need to define a request.onload() function. This function will be called after the response is received. so your JS code will be similar to this:
function checkChannel() {
if (localStorage.getItem('channel')) {
const channel = localStorage.getItem('channel');
const request = new XMLHttpRequest();
request.open('POST', '/convert');
// Add data to send with request
const data = new FormData();
data.append('channel', channel);
// Send request
request.send(data);
// 4. This will be called after the response is received
request.onload = function() {
if (request.status != 200) {
// analyze HTTP status of the response
alert(`Error ${request.status}: ${request.statusText}`);
// e.g. 404: Not Found
} else { // show the result
$('body').html(request.response)
}
};
}
}
Please note that you can replace $('body').html('some content') by $('div').html('some content') or $('#some-id').html('some content') based on channel.html file content.
Please find this example.
I'm building a tracking library to send events to the backend. An event should be created every 5 seconds (configurable) and sent into the tracking queue, and the tracking queue should be sent to the backend and emptied every 5 seconds (also configurable). The expected behaviour is that an event should be sent to the backend every 5 seconds.
When I was just console.logging the events, everything was working as expected, but when I implemented the xhr request, the interval events were only created every 9 seconds or so. So an event would be sent to the backend, only once every two times the 'post' function fired.
sendData: function(){
var toSend = [].concat(Tracking.__tracking_queue);
if(toSend.length !== 0){
var sendData = this.__stringifyAndSetHeaders(toSend);
Tracking.postData(sendData);
}
},
postData: function(sendData){
var xhr = new XMLHttpRequest();
xhr.onload = function() {
console.log(xhr.responseText);
Tracking.__tracking_queue = [];
};
xhr.open("POST", sendData.url, true);
Object.keys(sendData.headers).forEach(function(key){
xhr.setRequestHeader([key], sendData.headers[key]);
});
xhr.send(sendData.body);
}
The backend is receiving the data, but not at the correct times. sendData is being called from within a setInterval loop.
setInterval(function(){
self.sendData()
}, 5000);
I had the same setup working perfectly before, in another file using axios, but I cannot use axios in this use-case.
You are resetting the tracking data at the wrong location. You read the data, than make a request, after the request is done, you delete the data. There is a period of time where data can come into the queue between the request and when it finishes.
sendData: function(){
var toSend = [].concat(Tracking.__tracking_queue);
if(toSend.length !== 0){
var sendData = this.__stringifyAndSetHeaders(toSend);
Tracking.__tracking_queue = []; //clear it here
Tracking.postData(sendData);
}
},
postData: function(sendData){
var xhr = new XMLHttpRequest();
xhr.onload = function() {
console.log(xhr.responseText);
//Tracking.__tracking_queue = []; //don't clear it here
};
xhr.open("POST", sendData.url, true);
Object.keys(sendData.headers).forEach(function(key){
xhr.setRequestHeader([key], sendData.headers[key]);
});
xhr.send(sendData.body);
}
I have a simple chat done with long polling. The chat has 2 rows of conversations (or more). Each row has a unique id and a number of messages to show.
When I click on the first line, to show the messages of this conversation, I start an ajax, and it keeps persisting inside a loop in the serverside. However, when I click on the second line, I need to end the previous ajax and start a new one.
I tried some options like the ones below, but I did not find a solution.
$('li.chat-conversation').on('click', function(){
var requestRunning = true;
var xhr;
var id = $(this).attr('data-conversation-id');
var ajaxOpt = {...};
var fn = function(){
xhr = $.ajax(ajaxOpt);
if(requestRunning){
xhr.abort();
requestRunning = false;
}
};
var interval = setInterval(fn, 2000);
});
Can anyone help me figure out a logic for this?
Note: setInterval is for example only.
Move xhr outside of click handler scope and check if it exists on click event:
var xhr = null;
$('li.chat-conversation').on('click', function() {
var id = $(this).data('conversation-id');
var ajaxOpt = {...};
// when ajax request finished (does not matter success or failed)
ajaxOpt.complete = function() {
xhr = null;
};
if(xhr) {
xhr.abort();
}
xhr = $.ajax(ajaxOpt);
});
P.S. Extend my example Yourself (:
It turns out that the server response is inserted into a div by "append". And when I click on another conversation, they are running 2
ajax at the same time. And the div is changing content, that is, in a
request, append the messages of the first conversation and in the
other request, append the messages of the second conversation.
Just check the xhr.readystate value and if it isn't 4, abort the request and clear out the conversation related to that request.
Keeping track of active requests with your own Boolean flag can easily get out of sync with multiple requests if you are not setting the flag in all the right places. But the readystate property makes it so we don't have to manage any of that.
Also, you may need to cancel your interval timer when you cancel the AJAX request.
$('li.chat-conversation').on('click', function(){
var xhr = null;
var id = $(this).attr('data-conversation-id');
var ajaxOpt = {...};
var fn = function(){
xhr = $.ajax(ajaxOpt);
// Just check the readystate and if it's not 4 (DONE),
// then cancel the current request.
if(xhr.readystate !== 4){
// Cancel the previous AJAX call(s)
xhr.abort();
// Clear out the conversation related to the request
yourConversationDiv.textContent = "";
} else if(xhr.readystate === 4 && xhr.status === 200){
// Successful result, append to existing conversation
yourConversationDiv.append(xhr.responseText);
}
};
});