I would like to make buttons in my HTML while one of my JS classes is running and receives a response from the backend. I'm using jQuery and vanilla JS and created an example below. In this example, I'd like to dynamically disable the button that was not clicked to show the user that something is happening and that they should not click elsewhere until a response is returned.
Array.from(document.getElementsByClassName("upload-button")).forEach(button => {
button.addEventListener("click",
function(){
let buttonSpinner = this.getElementsByTagName("span")[0];
buttonSpinner.classList.remove("d-none");
// here I would like to disable the button that wasn't selected
let destination = this.value;
uploadData(destination, buttonSpinner);
}
)
})
function uploadData(destination, buttonSpinner){
let link = "https://www.google.com/";
let description = "Stack Overflow";
new Upload(link, description, destination, buttonSpinner)
}
class Upload {
constructor(link=null, description=null, destination="submit", buttonSpinner=null){
this.link = link;
this.description = description;
this.destination = destination;
this.buttonSpinner = buttonSpinner;
this.log();
this.disableButtonSpinner();
}
log(){
console.log(this.link)
}
wait(){
return new Promise(resolve => setTimeout(resolve, 3000)); // wait for data to return from backend
}
async disableButtonSpinner(){
await this.wait() // simulate backend returning data
this.buttonSpinner.classList.add("d-none");
}
}
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<div>
<button id="upload-user-data-button" value="data">
Upload & View My Data
<span role="status" aria-hidden="true"></span>
<span >Loading...</span>
</button>
<button id="upload-submit-button" value="submit">
Upload & Submit
<span role="status" aria-hidden="true"></span>
<span >Loading...</span>
</button>
</div>
CodePudding user response:
You can add a parameter in the function to access the click event I used e. Then You can loop through your buttons and disable other than events target. This is achieved by Array.from(document.getElementsByClassName("upload-button")).forEach(insideButton => { if(e.target !== insideButton) insideButton.disabled = true});
Array.from(document.getElementsByClassName("upload-button")).forEach(button => {
button.addEventListener("click",
function(e){
let buttonSpinner = this.getElementsByTagName("span")[0];
buttonSpinner.classList.remove("d-none");
// here I would like to disable the button that wasn't selected
Array.from(document.getElementsByClassName("upload-button")).forEach(insideButton => {
if(e.target !== insideButton)
insideButton.disabled = true});
let destination = this.value;
uploadData(destination, buttonSpinner);
}
)
})
function uploadData(destination, buttonSpinner){
let link = "https://www.google.com/";
let description = "Stack Overflow";
new Upload(link, description, destination, buttonSpinner)
}
class Upload {
constructor(link=null, description=null, destination="submit", buttonSpinner=null){
this.link = link;
this.description = description;
this.destination = destination;
this.buttonSpinner = buttonSpinner;
this.log();
this.disableButtonSpinner();
}
log(){
console.log(this.link)
}
wait(){
return new Promise(resolve => setTimeout(resolve, 3000)); // wait for data to return from backend
}
async disableButtonSpinner(){
await this.wait() // simulate backend returning data
this.buttonSpinner.classList.add("d-none");
}
}
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<div>
<button id="upload-user-data-button" value="data">
Upload & View My Data
<span role="status" aria-hidden="true"></span>
<span >Loading...</span>
</button>
<button id="upload-submit-button" value="submit">
Upload & Submit
<span role="status" aria-hidden="true"></span>
<span >Loading...</span>
</button>
</div>
CodePudding user response:
As a quick hack you could do something like that:
Array.from(document.getElementsByClassName("upload-button")).forEach((button, i) => {
button.addEventListener("click",
function(){
let buttonSpinner = this.getElementsByTagName("span")[0];
buttonSpinner.classList.remove("d-none");
// here I would like to disable the button that wasn't selected
let buttons = Array.from(document.getElementsByClassName("upload-button"))
if(i==0) buttons[1].disabled=true;
if(i==1) buttons[0].disabled=true;
let destination = this.value;
uploadData(destination, buttonSpinner);
}
)
})
function uploadData(destination, buttonSpinner){
let link = "https://www.google.com/";
let description = "Stack Overflow";
new Upload(link, description, destination, buttonSpinner)
}
class Upload {
constructor(link=null, description=null, destination="submit", buttonSpinner=null){
this.link = link;
this.description = description;
this.destination = destination;
this.buttonSpinner = buttonSpinner;
this.log();
this.disableButtonSpinner();
}
log(){
console.log(this.link)
}
wait(){
return new Promise(resolve => setTimeout(resolve, 3000)); // wait for data to return from backend
}
async disableButtonSpinner(){
await this.wait() // simulate backend returning data
this.buttonSpinner.classList.add("d-none");
let buttons = Array.from(document.getElementsByClassName("upload-button"))
buttons[0].disabled=false;
buttons[1].disabled=false;
}
}
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<div>
<button id="upload-user-data-button" value="data">
Upload & View My Data
<span role="status" aria-hidden="true"></span>
<span >Loading...</span>
</button>
<button id="upload-submit-button" value="submit">
Upload & Submit
<span role="status" aria-hidden="true"></span>
<span >Loading...</span>
</button>
</div>
CodePudding user response:
adding this solution to fix the issue with @Raven solution where the buttons remain disables even after the operation is done.
Array.from(document.getElementsByClassName("upload-button")).forEach(button => {
button.addEventListener("click",
async function(e){
let buttonSpinner = this.getElementsByTagName("span")[0];
buttonSpinner.classList.remove("d-none");
// here I would like to disable the button that wasn't selected
Array.from(document.getElementsByClassName("upload-button")).forEach(insideButton => {
if(e.target !== insideButton)
insideButton.disabled = true}
);
let destination = this.value;
await uploadData(destination, buttonSpinner);
}
)
})
async function uploadData(destination, buttonSpinner){
let link = "https://www.google.com/";
let description = "Stack Overflow";
await new Upload(link, description, destination, buttonSpinner)
}
class Upload {
constructor(link=null, description=null, destination="submit", buttonSpinner=null){
this.link = link;
this.description = description;
this.destination = destination;
this.buttonSpinner = buttonSpinner;
this.log();
this.disableButtonSpinner();
}
log(){
console.log(this.link)
}
wait(){
return new Promise(resolve => setTimeout(resolve, 3000)); // wait for data to return from backend
}
async disableButtonSpinner(){
await this.wait().then(()=>{
Array.from(document.getElementsByClassName("upload-button")).forEach(insideButton => {
insideButton.disabled = false;
}
);
}) // simulate backend returning data
this.buttonSpinner.classList.add("d-none");
}
}
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<div>
<button id="upload-user-data-button" value="data">
Upload & View My Data
<span role="status" aria-hidden="true"></span>
<span >Loading...</span>
</button>
<button id="upload-submit-button" value="submit">
Upload & Submit
<span role="status" aria-hidden="true"></span>
<span >Loading...</span>
</button>
</div>