Combine client-side and server-side validation in Bootstrap 4 form
Asked Answered
S

2

8

I have a Bootstrap 4 form with an input field, called runname. I want to perform the following validation on the input field:

  • runname cannot be empty
  • runname cannot contain spaces
  • runnamecannot already be used previously

I already have the code for a form which gives an error, using custom Bootstrap styles if the input field is empty:

// JavaScript for disabling form submissions if there are invalid fields
(function() {
  'use strict';
  window.addEventListener('load', function() {
    // Fetch all the forms we want to apply custom Bootstrap validation styles to
    var forms = document.getElementsByClassName('needs-validation');
    // Loop over them and prevent submission
    var validation = Array.prototype.filter.call(forms, function(form) {
      form.addEventListener('submit', function(event) {
        if (form.checkValidity() === false) {
          event.preventDefault();
          event.stopPropagation();
        }
        form.classList.add('was-validated');
      }, false);
    });
  }, false);
})();
<html lang="en">

<head>
  <!-- Required meta tags -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <!-- Bootstrap CSS -->
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">
</head>

<body class="bg-light">
  <div class="container">
    <div class="col-md-12 order-md1">
      <form class="needs-validation" novalidate method="post" action="#">
        <div class="form-group row">
          <label for="inputRunname" class="col-sm-2 col-form-label">Run name</label>
          <div class="col-sm-10">
            <input type="text" class="form-control" id="inputRunname" name="runname" placeholder="Run name" required>
            <div class="invalid-feedback">
              Please enter a run name
            </div>
          </div>
        </div>
        <div class="form-group row">
          <div class="col-sm-10">
            <button type="submit" class="btn btn-primary">Submit</button>
          </div>
        </div>
      </form>
    </div>
  </div>
  <!-- Optional JavaScript -->
  <!-- jQuery first, then Popper.js, then Bootstrap JS -->
  <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous"></script>

</body>

</html>

And I have some Javascript to check if an input contains spaces:

function cannotContainWhiteSpace(input, errorId, name) {
  var value = input.value;
  var errMsgHolder = document.getElementById(errorId);
  if (!(/^\S*$/.test(value))) {
    errMsgHolder.innerHTML =
      'The ' + name + ' cannot contain whitespace';
    input.focus();
    return false;
  }
}

And I also have some Python code on my Cherrypy backend which does a lookup in the database to see if the runname already exists:

try:
    myConnection = mysql.connector.connect(host=self.database['host'], user=self.database['user'], passwd=self.database['passwd'], db=self.database['db'])
    cursor = myConnection.cursor(buffered=True)

    # unless overriden by the force flag, check whether the runname has already been used before
    if not force:
        reusedrunquery = "SELECT run FROM logs WHERE run = %s AND errormessage IS NULL"
        cursor.execute(reusedrunquery, (runname,))
        if cursor.fetchall():
            flag = True
            cherrypy.session['reusedRun'] = True
    myConnection.close()
except mysql.connector.Error as err:
    return self.database_failure(str(err))

But I don't know how to cobble all these different parts together to get a form where I have both the two client-side validations and the server-side validation.

Sphygmomanometer answered 6/7, 2018 at 7:40 Comment(1)
I think you can just combine all form validation on form submit.however server side logic related check should be handle seperatlyFinstad
F
3

On Submit event, you should have a method in your backend that actually intercepts the request and I think there you should be able to make a connection with your backend's logic.

Here they are the steps:

  1. Form compiled correctly
  2. Http POST request starts onSubmit event
  3. Back-end receives the request and applies further logic by gathering the data on the method in charge to receive the Http POST request

Otherwise, you may try to make an AJAX call on which there will be executed the client-side validations and then it will call the server-side method/class for checking that runname has been used already.

Fasciate answered 16/7, 2018 at 7:42 Comment(0)
R
2

Most of the times I use custom styles to achieve this.

.invalid-feedback{
  display:none;
}

.invalid .invalid-feedback {
  display:block;
}
<form novalidate>
  <div class="form-group">
    <label>Label</label>
    <input class="form-control" name="runname" type="text">
    <div class="invalid-feedback"></div>
  </div>
</form>

In Javascript

Validate the input controls and set css classes and message text.In your case, validate not empty, no spaces, and not already used[server side]. If invalid add the class invalid to parent form-group, and set the validation message inside invalid-feedback div next to the input control.

Roundly answered 16/7, 2018 at 7:56 Comment(1)
Well it doesnt update the message after showing server side error message. Ex: I displayed "Email is already taken." in invalid-feedback element. Then, I clear email field and try to submit. It didn't show the right message for empty field. Is there anyway to handdle that?Tarentarentum

© 2022 - 2024 — McMap. All rights reserved.