Stop Form Submission in Bootstrap 5

I require assistance with identifying the issue in the JavaScript code provided below. I am working with a Bootstrap 5 form where the submission is not being prevented if the fields are left blank or invalid. While the HTML/CSS validation works correctly for invalid fields, the submission is still allowed.

My JavaScript skills are not very advanced, so I would greatly appreciate any help!

(function () {
    "use strict";

    // Select all forms that require custom Bootstrap validation
    let forms = document.querySelectorAll(".needs-validation");

    // Prevent form submission for invalid forms
    Array.from(forms).forEach(function (form) {
            form.addEventListener("submit", function (event) {
                 if (!form.checkValidity()) {
                        event.preventDefault();
                        event.stopPropagation();
                    }
                        form.classList.add("was-validated");
                    }, false
            );
    });

    forms.forEach( function(e) {
    e.addEventListener('submit', function(event) {
      event.preventDefault();

      let thisForm = this;

      let action = thisForm.getAttribute('action');
      let recaptcha = thisForm.getAttribute('data-recaptcha-site-key');

      if( ! action ) {
        displayError(thisForm, 'The form action property is not set!')
        return;
      }
      thisForm.querySelector('.loading').classList.add('d-block');
      thisForm.querySelector('.error-message').classList.remove('d-block');
      thisForm.querySelector('.sent-message').classList.remove('d-block');

      let formData = new FormData( thisForm );

      if ( recaptcha ) {
        if(typeof grecaptcha !== "undefined" ) {
          grecaptcha.ready(function() {
            try {
              grecaptcha.execute(recaptcha, {action: 'php_email_form_submit'})
              .then(token => {
                formData.set('recaptcha-response', token);
                php_email_form_submit(thisForm, action, formData);
              })
            } catch(error) {
              displayError(thisForm, error)
            }
          });
        } else {
          displayError(thisForm, 'The reCaptcha javascript API url is not loaded!')
        }
      } else {
        php_email_form_submit(thisForm, action, formData);
      }
    });
  });

  function php_email_form_submit(thisForm, action, formData) {
    fetch(action, {
      method: 'POST',
      body: formData,
      headers: {'X-Requested-With': 'XMLHttpRequest'}
    })
    .then(response => {
      if( response.ok ) {
        return response.json()
      } else {
        throw new Error(`${response.status} ${response.statusText} ${response.url}`);
      }
    })
    .then(data => {
      thisForm.querySelector('.loading').classList.remove('d-block');
      if (data.type === 'success') {
        thisForm.querySelector('.sent-message').classList.add('d-block');
        thisForm.reset();
      } else {
        throw new Error(data ? data : 'Form submission failed and no error message returned from: ' + action);
      }
    })
    .catch((error) => {
      displayError(thisForm, error);
    });
  }

  function displayError(thisForm, error) {
    thisForm.querySelector('.loading').classList.remove('d-block');
    thisForm.querySelector('.error-message').innerHTML = error;
    thisForm.querySelector('.error-message').classList.add('d-block');
  }

})();

Answer №1

To make sure that the event.stopPropagation() command in the initial statement works, you need to pass true instead of false to the useCapture parameter of the addEventListener function.

Otherwise, both events will occur simultaneously without one taking precedence over the other, and stopPropagation will only prevent the bubbling of the submit event, which may not align with your desired outcome.

Edit: Another approach, as suggested in the comments, is to combine validation and code execution within the same event listener.

// code before ...
forms.forEach(function(e) {
    e.addEventListener('submit', function(event) {
        event.preventDefault();
        
        if (!e.checkValidity()) {
            e.removeClass("was-validated");
            return; // halts the code due to invalid input
        }
        
        e.addClass("was-validated");
        //...rest of the code
    })
});
// code after ...

Side note: In Firefox, you may need to use event.stopImmediatePropagation() to achieve similar behavior.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Ways to update list item text with jQuery

I am attempting to create a button that can replace the content of a list item. Although I have looked at other solutions, I keep encountering this error message: Uncaught TypeError: Object li#element2 has no method 'replaceWith' I have experime ...

How can I dynamically populate a multiple select box with data from a PHP query and store it in a multidimensional array using jQuery?

I apologize for any language barriers as English is not my first language. My query is as follows, I am looking to implement three multiple select boxes on a single page. How can I retrieve query data before it is executed in PHP? Each loop result will be ...

Using JavaScript functions within PHP is not supported

Currently, I am utilizing Laravel for my backend operations. Within my setup, there exists a JavaScript function called StartJob() that facilitates Google crawling. In the scenario where I input a keyword, which is then cross-referenced with the database, ...

Creating balanced numerical values within the range of 0 to 1 using an array

Is there a way to create a set of numbers between 0 and 1 that is proportional to an array of sales with varying sizes? For instance, if the sales values are [1, 80, 2000], would it be possible to generate an array like [0.1, 0.4, 1]? ...

Several different forms are present on a single page, and the goal is to submit all of the data at

Looking for assistance with combining Twitter and Google data entry at once. Here's the code I've developed: Please guide me on how to submit Twitter and Google details together. <html> <head> <script type="text/javascript">< ...

What is the best way to initially hide a div using slide toggle and then reveal it upon clicking?

Is there a way to initially hide the div tag and then animate it in a slide toggle effect? I attempted using display:none on my '.accordion_box' followed by show() in slideToggle, but this results in adding the CSS property display: block. My goa ...

Monitoring the progress of file uploads within itemView

In the process of developing an application using Marionette/Backbone, I have successfully implemented file uploads over an AJAX call. Now, I am looking for a way to provide users with feedback on when they can select the uploaded file and proceed with mod ...

"Encountered an issue: Error occurred while attempting to synchronize Protractor with the page" during the execution of Protractor tests

I am facing an issue while running Protractor tests on a web application that includes both Angular and non-angular elements. Here is the structure of my code: describe("Test Name", function() { it("Test case", function() { // starting with steps on ...

Unable to access property 'scrollToBottom' as it is undefined

I'm encountering the error "Cannot read property 'scrollToBottom' of undefined" and haven't been able to find a solution anywhere, hence this post: Here is my use case: I have a custom accordion list, and on click of one of the list i ...

Utilizing a function as an argument in another function (with specified parameters)

I’m stuck and can’t seem to solve this problem. In my function, the parameter filter needs to be a function call that accepts an object created within the same function: function bindSlider(time, filter) { var values = { min : 8, max : ...

Issue with Bootstrap 5 spinner's lack of motion in Firefox browser

Essentially, the issue is that a very simple Bootstrap 5 spinner does not spin in Firefox. It works fine in Chromium and all other Bootstrap components work well in Firefox as well. Here is the html code (identical to Bootstrap docs): <div class=&q ...

What makes the state display potential when utilizing Redux? Also, what is the best approach to access the array within the outcome?

Upon logging the state here, I noticed a promising result. However, I am struggling to access the array inside the promise outcome. I attempted using Object.keys and map but was unsuccessful. > import React, { useEffect, useState } from 'react&apos ...

Sending Data from Clicked Button to Another Component as a Prop

I am struggling to figure out how to pass a value that is set inside a button to a child component. Essentially, I want the value of the clicked button that displays a percentage to be passed as a prop value. This prop value should update depending on whic ...

Is there a way to use SCTP with Socket.io and Node.js?

I have a new project in the works, creating a web application that will utilize web sockets to provide real-time updates for users. The plan is to seamlessly transmit changes from the back-end engine. My challenge lies in Node.js not supporting SCTP sock ...

Looking for a way to access the source code of a QML method in C++?

I'm currently working on serializing objects to QML and I am looking for a way to retrieve the source code of functions defined within a QML object. Let's consider the following example in QML (test.qml): import QtQml 2.2 QtObject { functio ...

Is there a way to update prop values after the page has been reloaded in Vue?

Here is the code snippet I am working with: I have created an example and I am trying to access the props values in the onMounted() function. However, when I console.log(account.value.date), it returns undefined. Is there a way to modify the props values ...

Utilizing jQuery to dynamically update background colors within an ASP repeater based on the selected value of a dropdown list

On my asp.net web page, I have a repeater that displays a table with various fields in each row. I am trying to make it so that when the value of a dropdown within a repeater row changes, the entire row is highlighted in color. While I have achieved this s ...

Using a pipe filter to implement a search feature in an Ionic search bar

Hey everyone, I'm facing a little issue here. I created a pipe filter to sort through some data, but now I need to include two more filters and I'm not sure how to go about it within this pipe. Below is an example of the pipe I have created: ...

Running repetitive tasks in PHP using setInterval function

I've been working on adding a "friend request" feature to my website and I really want the requests to show up instantly without having to reload the page. After doing some research, it seems like using setInterval with Ajax is the way to go. I found ...

Templating with Underscores: Revolutionizing token markers

When using out of the box underscore templating, the default markers for raw content are <%= %>, and for HTML escaped content are <%- %>. However, it is possible to change these markers by adjusting the template settings, for example: _.templ ...