DOM exception 11 - javascript

I'm running this code via the console on http://TheScoutApp.com on line 3 I'm getting a DOM exception 11!!!
var xhr2 = new XMLHttpRequest();
xhr2.onreadystatechange = function() {
console.error(xhr2.statusText); //DOM exception 11!!!
if (xhr2.readyState === 4 && xhr2.status === 200) {
console.error('xhr2');
}
}
xhr2.open("GET","http://thescoutapp.com/extension/update.xml",true);
xhr2.send();

The property xhr.statusText may only be accessed after the request is finished. But the onreadystatechange-callback gets called erlier - the earlier calls have xhr.readyState==1 (=server connection established).
You have to put the assess of xhr.statusText inside a condition:
if(xhr.readyState == 4) {
console.error(xhr.statusText);
}

Related

How to make callback run asynchronously?

I have a JavaScript function called getAandB which takes a callback. getAandB firstly gets value 'a' using ajax. It then invokes the callback with value 'a' as an argument. The callback gets value 'b' and console.logs both 'a' and 'b' to the console. so I get {"key":"a"} {"key":"b"} in the console.
I thought that the two ajax calls would happen simultaneously / asynchronously. However, they seem to run one after the other ie. synchronously.
The JavaScript code and the PHP code for the ajax requests is shown below:
index.html:
<script>
function getAandB(callback){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-a.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
callback(xhr.responseText)
}
}
xhr.send();
}
function callback(resultA){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-b.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
const resultB = xhr.responseText;
console.log(resultA, resultB);
}
}
xhr.send();
}
getAandB(callback);
</script>
ajax-a.php:
<?php
sleep(5);
$response = [
"key" => "a",
];
echo json_encode($response);
The code for ajax-b.php is the same as for ajax-a.php except the value of $response.key is b not a.
I thought that the above code would result in ajax calls being made simultaneously to get 'a' and 'b'. However if the PHP code sleeps for 5 seconds for both ajax-a.php and ajax-b.php, then it takes 10 seconds for the console.log to appear. If only one of the ajax-?.php scripts sleeps for 5 seconds then it takes 5 seconds for the console.log to appear.
How can I use callbacks to allow me to combine the results of ajax calls, as I have done here, but to make the individual calls happen simultaneously / asynchronously? Alternatively, is not possible to implement this with callbacks?
If you want the request to ajax-b to me made at approximately the same time as the request for ajax-a then you need to make the respective calls to xhr.send() at approximately the same time.
At the moment, the call to ajax-b's send() takes place as part of callback() which you only call after you have received the response to the request for ajax-a.
You then need to add additional logic to determine when you have received both responses so you log both bits of data at the same time (assuming you still want to do that).
A rough and ready way to do that, keeping to your current approach, would look something like this:
function getA(callback){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-a.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
callback(xhr.responseText)
}
}
xhr.send();
}
function getB(callback){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-b.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
const resultB = xhr.responseText;
callback(xhr.responseText)
}
}
xhr.send();
}
function getAandB() {
const data = [];
function callback(responseData) {
data.push(responseData);
if (data.length === 2) {
console.log(...data);
}
}
getA(callback);
getB(callback);
}
getAandB();
We have better tools for that these days though, thanks to promises and modern APIs (like fetch) which support them natively.
async function getAandB() {
const dataPromises = [
fetch("./ajax-a.php").then(r => r.text()),
fetch("./ajax-b.php").then(r => r.text())
];
const data = await Promise.all(dataPromises);
console.log(...data);
}
getAandB();
I tried to edit my question but 'the edit queue was full'.
It took me a while to understand #Quentin's answer but I finally realized it relies on the fact that both instantiations of the callback function are altering the same variable (I think that is called by reference and is the default situation with arrays). Given this, although the instantiations know nothing about each other, it is possible to know when both ajax calls have completed by checking to see if the data array has been updated twice. If it has then both must have completed and data can be consoled out.
There is no need for the getAandB function. This much simpler and less confusing code works exactly the same as Quentin's answer:
<script>
const data = [];
function getA(){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-a.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
data.push(xhr.responseText);
if (data.length === 2){
console.log(...data);
}
}
}
xhr.send();
}
function getB(){
const xhr = new XMLHttpRequest();
xhr.open('GET', './ajax-b.php', true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
data.push(xhr.responseText);
if (data.length === 2){
console.log(...data);
}
}
}
xhr.send();
}
getA();
getB();
</script>

Why if and else both condition executing at same time in JavaScript | If and Else Condition

Why If and else condition work both in JavaScript. if (xhr.readyState == 4 && xhr.status == 200)
I am working on php MVC project.
I created a profile edit page in background JavaScript If and Else both code executing. profile edit Successfully but else code work and it's show error "Sorry, this content isn't available right now".
why this else condition work??
same This code work in login and registration page.
save in local file and run than it work :-
online code
Code
document.querySelector("#Profile_Save").addEventListener("click", () => {
if (document.querySelector("#Profile_Edit_Email").value.match(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+#[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/)) {
document.querySelector("#Profile_Edit_Msg").classList.remove("active_success");
document.querySelector("#Profile_Edit_Msg").classList.remove("active_denger");
document.querySelector("#Profile_Save").innerHTML = "Loading...";
document.querySelector("#Profile_Save").classList.remove("active");
document.querySelector("#Profile_Save").disabled = true;
document.querySelector("#Profile_Edit_F_Name").disabled = true;
document.querySelector("#Profile_Edit_L_Name").disabled = true;
document.querySelector("#Profile_Edit_Email").disabled = true;
var f_name = document.querySelector("#Profile_Edit_F_Name").value,
l_name = document.querySelector("#Profile_Edit_L_Name").value,
email = document.querySelector("#Profile_Edit_Email").value;
var xhr = new XMLHttpRequest();
xhr.open("POST", "Api/ProfileEdit", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) { // this one if executing
var json = JSON.parse(xhr.responseText);
if (json.Status == "Ok") {
window.location.href = "Profile"; // it also work
} else {
document.querySelector("#Profile_Edit_Msg").classList.remove("active_success");
document.querySelector("#Profile_Edit_Msg").classList.add("active_denger");
document.querySelector("#Profile_Edit_Msg").innerHTML = json.Message;
}
} else { // this one else executing
document.querySelector("#Profile_Edit_Msg").classList.add("active_denger");
document.querySelector("#Profile_Edit_Msg").innerHTML = "Sorry, this content isn't available right now"; // this message show
}
}
xhr.send("F_Name=" + f_name + "&L_Name=" + l_name + "&Email=" + email);
document.querySelector("#Profile_Save").innerHTML = "Register";
document.querySelector("#Profile_Save").classList.add("active");
document.querySelector("#Profile_Save").disabled = false;
document.querySelector("#Profile_Edit_F_Name").disabled = false;
document.querySelector("#Profile_Edit_L_Name").disabled = false;
document.querySelector("#Profile_Edit_Email").disabled = false;
} else {
document.querySelector("#Profile_Edit_Msg").classList.add("active_denger");
document.querySelector("#Profile_Edit_Msg").innerHTML = "Invalid Email Address!";
}
});
return JSON
{"Status":"Ok","Message":"Profile Edit Successfully!"}
Output
open profile page and
error message:- "Sorry, this content isn't available right now"
help me!
Thank you!!
The readystatechange event fires multiple times.
Value State Description
0 UNSENT Client has been created. open() not called yet.
1 OPENED open() has been called.
2 HEADERS_RECEIVED send() has been called, and headers and status are available.
3 LOADING Downloading; responseText holds partial data.
4 DONE The operation is complete.
Your
if (xhr.readyState == 4 && xhr.status == 200) {
branch will only be entered into at the end of a request, if the request was successful. But earlier, while the request is still ongoing, other state changes will occur, and the else branch will be entered into.
Instead, only do anything if the readyState is 4 - and, when it is 4, you can parse the response, or populate the #Profile_Edit_Msg to say there was a problem.
Other improvements:
Save the Profile_Edit_Msg in a variable instead of repetitively selecting it over and over again
Use strict equality, not sloppy equality
Use .textContent when assigning text to an element - only use .innerHTML when inserting HTML markup
JSON is a particular format of a string that can be deserialized into an object or other value. JSON.parse does not return JSON - JSON.parse is called with a JSON-formatted string and returns an object. Call your json variable something else.
denger looks misspelled - did you mean danger? (Typos are a common problem in programming - better to fix them earlier than later)
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) {
return;
}
const profile = document.querySelector("#Profile_Edit_Msg");
if (xhr.status === 200) {
const result = JSON.parse(xhr.responseText);
if (result.Status === "Ok") {
window.location.href = "Profile";
} else {
profile.classList.remove("active_success");
profile.classList.add("active_denger");
profile.innerHTML = json.Message;
}
} else {
profile.classList.add("active_denger");
profile.textContent = "Sorry, this content isn't available right now";
}
};
You could also consider using the fetch API instead of XMLHttpRequest - fetch is a bit nicer to work with and has been supported in all modern browsers for ages.

Why Promise return an empty string?

I have a function foo which makes an Ajax request.
I tried returning the data from the callback and got the data with "xhr.onload" successfully but got an empty string("") with "xhr.onreadystatechange".
Could anyone tell me why??
Thank you very much!
function foo(url){
return new Promise(function(resolve,reject){
var xhr = new XMLHttpRequest();
xhr.open("GET",url,true);
// xhr.onload = function(){
// if(xhr.status == 200){
// resolve(xhr.responseText);
// }else{
// reject("false")
// }
// }
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState && xhr.status == 200){
resolve(xhr.responseText);
}else{
reject("false")
}
}
})
}
foo(url).then(function (data){
console.log(data)
},function (err){
console.log(err)
})
Your onreadystatechange handler is incorrect. You need to check readyState for the value 4 (not just any truthy value), and you don't want to reject until readyState is 4:
if(xhr.readyState === 4){
if (xhr.status == 200) { // or xhr.status >= 200 && xhr.status < 300
resolve(xhr.responseText);
} else {
reject("false")
}
}
But with modern browsers, you'd probably use fetch instead, which already provides a promise. Just be sure not to make these common mistakes (that's a post on my anemic little blog).
As for why you were seeing what you were seeing, since you called open and send before attaching the handler apparently you didn't get the callback for readyState 1 (opened), so it looks like the first callback you got was when the headers were received (readyState 2), at which point xhr.status would be set — so you were resolving your promise, but of course, the request body hadn't been received yet.

XHR calls return empty

I am new to AJAX and I am trying to make a call to my json file but it is not returning anything in console. I looked into network tab, the xhr status is 200.
const xhr = new XMLHttpRequest();
xhr.readyState = function(){
if(xhr.readyState === 4){
console.log(xhr.responseText)
}
}
xhr.open('GET','data/task.json');
xhr.send();
and task.json is
{
"jobs": [
{
"id": 7,
"title": "Clerk",
"employer": {
"name": "AOL"
},
"location": "Floria",
"salary": "$45k+"
}
]
}
I tried parsing it and using console to print it out but the console is empty as well.
There a few things to notice in the request that you are making.
You need to add the status to 200 because it's the OK status. Meaning that your request go through. So that part will exactly become (this.readyState == 4 && this.status == 200).
You also need to change from using triple equal signs === to == because you are not comparing by TYPE as a triple equals is used in JS.
Using the event handler xhttp.onreadystatechange instead of xmr.readySate. Here is a link to the Mozilla documentation.
So it should become:
const xhttp = new XMLHttpRequest();
xhttp.onreadystatechange= function(){
if(xhttp.readyState === 4 && xhttp.status == 200){
console.log(xhr.responseText)
}
}
xhr.open('GET','data/task.json');
xhr.send();
Here is a detailed documentation from W3Schools Documentation with example.
You need onreadystatechange not readyState
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
console.log(xhr.responseText)
}
}
xhr.open('GET','data/task.json');
xhr.send();
Instead of xhr.readyState you should use xhr.onreadystatechange
like that:
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
console.log(xhr.responseText)
}
}

Ajax readyState returning always 0

I've got a problem with this Ajax code, is returning 0 everytime I access 'readyState'. Don't know what the source of the problem is yet, any help would be appreciated:
var xhr = null;
function performAjax(inputUrl){
// instantiate XMLHttpRequest object
try{
xhr = new XMLHttpRequest();
alert("XMLHttpRequest");
}
catch(e){
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
// handle old browsers
if( xhr == null ) {
alert("Ajax not supported by your browser");
return;
}
// get the URL
var url = inputUrl;
alert(inputUrl);
// get Ajax answer
xhr.onreadystatechange = handler();
//alert(xhr.readyState);
xhr.open("POST", url, true);
xhr.send(null);
}
function handler() {
alert("Handler: " + xhr.readyState + " Status: " + xhr.status);
// handle only loaded requests
if(xhr.readyState == 4) { // state 4: that data has been received
alert("here");
if(xhr.status == 200) {
alert(xhr.reponseText);
}
else alert("Error with Ajax");
}
}
You're assigning the handler function incorrectly:
xhr.onreadystatechange = handler; // <--- THERE SHOULD BE NO PARENTHESES
When you include the parentheses, you're asking that the function be called. Without them, you're merely referring to the function, which is what you want.

Categories

Resources