title: Combine client-side and server-side validation in Bootstrap 4 form
body: <p>I have a Bootstrap 4 form with an input field, called <code>runname</code>. I want to perform the following validation on the input field:</p>
  
  <ul>
  <li><code>runname</code> cannot be empty</li>
  <li><code>runname</code> cannot contain spaces</li>
  <li><code>runname</code>cannot already be used previously</li>
  </ul>
  
  <p>I already have the code for a form which gives an error, using <a href="https://getbootstrap.com/docs/4.1/components/forms/#custom-styles" rel="noreferrer">custom Bootstrap styles</a> if the input field is empty:</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>// 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);
  })();</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;html lang="en"&gt;
  
  &lt;head&gt;
    &lt;!-- Required meta tags --&gt;
    &lt;meta charset="utf-8"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"&gt;
    &lt;!-- Bootstrap CSS --&gt;
    &lt;link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous"&gt;
  &lt;/head&gt;
  
  &lt;body class="bg-light"&gt;
    &lt;div class="container"&gt;
      &lt;div class="col-md-12 order-md1"&gt;
        &lt;form class="needs-validation" novalidate method="post" action="#"&gt;
          &lt;div class="form-group row"&gt;
            &lt;label for="inputRunname" class="col-sm-2 col-form-label"&gt;Run name&lt;/label&gt;
            &lt;div class="col-sm-10"&gt;
              &lt;input type="text" class="form-control" id="inputRunname" name="runname" placeholder="Run name" required&gt;
              &lt;div class="invalid-feedback"&gt;
                Please enter a run name
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
          &lt;div class="form-group row"&gt;
            &lt;div class="col-sm-10"&gt;
              &lt;button type="submit" class="btn btn-primary"&gt;Submit&lt;/button&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/form&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;!-- Optional JavaScript --&gt;
    &lt;!-- jQuery first, then Popper.js, then Bootstrap JS --&gt;
    &lt;script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"&gt;&lt;/script&gt;
    &lt;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"&gt;&lt;/script&gt;
    &lt;script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous"&gt;&lt;/script&gt;
  
  &lt;/body&gt;
  
  &lt;/html&gt;</code></pre>
  </div>
  </div>
  </p>
  
  <p>And I have some Javascript to check if an input contains spaces:</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>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;
    }
  }</code></pre>
  </div>
  </div>
  </p>
  
  <p>And I also have some Python code on my Cherrypy backend which does a lookup in the database to see if the <code>runname</code> already exists:</p>
  
  <pre><code>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))
  </code></pre>
  
  <p>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.</p>