What is the equivalent of this ternary operator expression? - javascript

I have to use a piece of code that comes from another company project.
Unfortunately, it contains an expression that triggers an error in SonarCloud.
The error is:
Non-empty statements should change control flow or have at least one side-effect
The colleague that wrote this line is not in the company anymore.
The line that needs to be modified is xhr.status === 200 ? observable.next(xhr.response), observable.complete()) : observable.error(xhr.statusText);.
Here is the full code:
sendMedia(file: File, presignedUrl: string): Observable<Object> {
return new Observable(observable => {
const xhr = new XMLHttpRequest();
xhr.open('PUT', presignedUrl, true);
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
xhr.status === 200 ?
(observable.next(xhr.response), observable.complete()) :
observable.error(xhr.statusText);
}
};
xhr.send(file);
});
}
If this block equivalent to that statement?
if (xhr.status === 200) {
return observable.next(xhr.response), observable.complete();
} else {
return observable.error(xhr.statusText);
}
Thanks a lot for anyone trying to help!

You are almost there except return statement
if (xhr.status === 200) {
observable.next(xhr.response);
observable.complete();
} else {
observable.error(xhr.statusText);
}

Related

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.

How to separate XMLHttpRequest from the main function for better visbility/testibility (without Promises / asnyc/await )

Imagine this function:
function myMainFunction() {
doSomeInitialStuff();
// more stuff..
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
// Now that we know we received the result, we can do the heavy lifting here
if (xhr.status == 200) {
console.log("ready 200");
let result = JSON.parse(xhr.responseText);
doStuff(result);
// and much more stuff..
} else {
console.log("error", xhr.status);
return undefined;
}
}
};
xhr.open("GET", "http://example.com", true);
xhr.send(null);
}
This works fine, but it is impossible to test, and this function has become a monster.
So I'd like to refactor it, by separating all the different parts in their own unique functions.
The problem is, I do not know how to extract the XHR part and still keep it working.
I cannot use Promises nor asnyc/await and have to stick to using plain XHR.
What I'd normally do is to create a seperate async function for the ajax call (or the xhr in this case). Simply await it's result and go from there. Easy to separate. But I do not have the luxury of await or anything this time.
What I am trying to get at is something like this
function refactoredMyMainFunction() {
doSomeInitialStuff();
// more stuff..
let result = xhrFunction();
doStuff(result); // result would be undefined here, since I cannot wait for the xhr request to finish.
}
You can implement a callback-based API:
function myMainFunction() {
doSomeInitialStuff();
// more stuff..
xhrFunction(doStuff);
}
function xhrFunction(cb) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
// Now that we know we received the result, we can do the heavy lifting here
if (xhr.status == 200) {
console.log("ready 200");
let result = JSON.parse(xhr.responseText);
cb(result);
// and much more stuff..
} else {
console.log("error", xhr.status);
return undefined;
}
}
};
xhr.open("GET", "http://example.com", true);
xhr.send(null);
}

Is a TypeError okay or should I use try/catch?

I have this simple AJAX-Class which works as expected in all browsers except Internet Explorer <6 (which I don't care too much):
var Ajax = function(url, callback) {
this.xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
this.xhr.open('GET', url, true);
this.xhr.onreadystatechange = function() {
if (this.readyState === 4 && this.status === 200) {
if (typeof callback === "function") {
callback(this.responseText);
}
}
}
this.xhr.send();
};
So, my question is if there would be any reason or advantage to add try/catch to prevent a TypeError in IE<6? Like this:
// ...
try {
this.xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
} catch(e) {
return;
}
// ...
Or is it okay to risk this error? Does it prevent further code from being executed or displays an ugly warning or anything that kind?

Ajax call issues more callbacks than expected

I have this code to make an ajax request, but according to Chrome Inspector the callback associated with the request is being called twice (by this I mean the response is being logged into the console twice), 2 more logs are being printed without any content. Here's the code:
var ajax = {
pull: function (settings) {
settings.type = 'get';
settings.callback = typeof (settings.callback) === 'function' ? settings.callback : false;
settings.data = settings.data ? settings.data : null;
return this.request(settings.url, settings.type, settings.callback, settings.data);
},
request: function (url, type, callback, data) {
var ids = ['MSXML2.XMLHTTP.3.0',
'MSXML2.XMLHTTP',
'Microsoft.XMLHTTP'],
xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
for (var i = 0; i < ids.length; i++) {
try {
xhr = new ActiveXObject(ids[i]);
break;
} catch (e) {}
}
}
if (callback) {
xhr.onreadystatechange = function () {
callback(xhr);
};
}
xhr.open(type, url, true);
if (type.toUpperCase() === 'GET') {
xhr.send();
} else if (type.toUpperCase() === 'POST') {
xhr.send(data);
}
}
}
ajax.pull({
url: 'http://localhost/my/twtools/scripts/ajax.php',
callback: function (xhr) {
console.log(xhr.response);
}
});
xhr.onreadystatechange has several steps (numbered from 0 top 4 I do believe something like 0 = uninitialized, 1 = starting etc, although I can't rember the exact names of the steps anymore, a quick google should find them), and each step is calling your callback. If I remember correctly, the last stage is 4, so I do believe you need to check something like this
if (xhr.readyState == 4 && xhr.status == 200)
{
// call has finished successfully
}
inside you callback, i.e. to check that it is all finished and got a successful response
I've been spoilt by jQuery these days (so much easier to do with jQuery), been quite a while since I wrote raw ajax
You're using onreadystatechange, which gets called more than once (once each state change).
Try using
xhr.onload = function() {
callback(xhr);
};

how to wait for all ajax calls to be done before testing with jasmine

I would like to wait before all remote files are loaded before I start testing my jasmine (because I don't want to handle waitsFor, spyes everywhere in my specfile, but only in the start of the file)
loadDoc is a function I created to load my remote files
loadDoc = function(path, callBack, noDocx) {
var xhrDoc;
if (noDocx == null) {
noDocx = false;
}
xhrDoc = new XMLHttpRequest();
docxCallback[path] = callBack;
xhrDoc.open('GET', "../examples/" + path, true);
if (xhrDoc.overrideMimeType) {
xhrDoc.overrideMimeType('text/plain; charset=x-user-defined');
}
xhrDoc.onreadystatechange = function(e) {
if (this.readyState === 4 && this.status === 200) {
window.docXData[path] = this.response;
if (noDocx === false) {
window.docX[path] = new DocxGen(this.response);
}
return docxCallback[path]();
}
};
return xhrDoc.send();
};
test:
describe("DocxGen", function() {
var globalcallBack;
globalcallBack = jasmine.createSpy();
loadDoc('imageExample.docx', globalcallBack);
loadDoc('image.png', globalcallBack, true);
....
waitsFor(function() {
return globalcallBack.callCount >= 10;
});
describe(...)
....
})
To solve this problem, I used synchronous Ajax Requests, so that the code execution of the Jasmine Block only starts after all the documents are loaded.
Here's my code at the beginning of the file (I assume that you want to store the files inside an array named fileLoaded.
window.fileLoaded=[]
DocUtils.loadDoc= function(path)
{
xhrDoc = new XMLHttpRequest();
xhrDoc.open('GET', path, false); //This line makes the call asynchronous (the false)
xhrDoc.onreadystatechange = function(e) {
if (this.readyState === 4) {
if (this.status === 200) {
window.fileLoaded[path]=this.response;
}
else {
console.log('error loading doc');
if (callback != null) {
return callback(true);
}
}
}
};
xhrDoc.send();
}
DocUtils.loadDoc('tagExampleExpected.docx')
DocUtils.loadDoc('tagLoopExample.docx')
DocUtils.loadDoc('tagLoopExampleImageExpected.docx')
DocUtils.loadDoc('tagProduitLoop.docx')

Categories

Resources