Home > Mobile >  How do you check if an input field is filled with whitespace using JavaScript?
How do you check if an input field is filled with whitespace using JavaScript?

Time:08-19

I have used JavaScript to disable a button until all the inputs are filled, but I also want to keep the button disabled if any input is filled only with whitespace. (I am not using a form because it interferes with my other code.) How do I check if the inputs have any character other than whitespace?

JavaScript code that disables the button once the inputs are filled:

document.addEventListener('DOMContentLoaded', function(){
    const required = document.querySelectorAll('.input');
    //gets all the quiz_buttons                                                                                                                                      
    const quizButton = document.querySelectorAll('.quiz_button');
    for (const i of required){
        i.addEventListener("input", checkSubmit);
    }
    for (const button of quizButton){
        button.disabled = true;
        button.addEventListener('click', (event) =>
            check_quiz(event.target.id));
    }

    function checkSubmit(){
        let isValid = true;
        for (const i of required){
            isValid = isValid && !!i.value;
        }

        for (const button of quizButton){
            button.disabled = !isValid;
        }
    }
});

CodePudding user response:

You can use every to check if each input.value has length, and - using a regex - doesn't have just whitespace.

// Cache the elements up-front. We coerce `input` to
// and array so we can use `every` later
const container = document.querySelector('.container');
const inputs = [...document.querySelectorAll('input')];
const button = document.querySelector('button');

// Hang on listener off the parent component - using
// event delegation we can catch events from its child
// elements when they're fired and "bubble up" the DOM
container.addEventListener('input', handleInput);

function handleInput(e) {

  // Check that the child element that fired the
  // event is an input element
  if (e.target.matches('input')) {

    // Use `every` to iterate over the inputs.
    // `every` returns a boolean - if the condition
    // isn't met it returns false, otherwise true.
    // Here the condition checks that the input has
    // length, and isn't just all whitespace
    let valid = inputs.every(input => {
      return input.value.length
        && !/^\s $/.test(input.value)    
    });

    // Disable/enable the button based
    // on the result
    button.disabled = valid ? false : true;
  }
}
<section >
  <input />
  <input />
  <input />
  <input />
</section>
<button disabled>Submit</button>

Additional documentation

The regex reads:

^   - start of string
\s  - one or more spaces
$   - end of string

CodePudding user response:

This can be done in both CSS/HTML and with JavaScript; though the HTML and CSS approach does make use of the :has() pseudo-class (currently limited to Safari, Chrome and Edge (the latter two behind a flag)):

// I don't like typing, so I use these helpers to cache the
// document, and aliases for querySelector() and querySelectorAll():
const D = document,
  get = (sel, context = D) => context.querySelector(sel),
  getAll = (sel, context = D) => [...context.querySelectorAll(sel)];

// if the browser's CSS interface does not have support for the
// selector of ":has(a)":
if (!CSS.supports('selector(:has(a))')) {
  // we retrieve all <label> elements:
  const labels = getAll('label'),
    // and all <input> elements:
    inputs = getAll('input'),
    // declare a function to check validity:
    checkValidity = () => {
      // we retrieve the <button> element:
      const button = get('button'),
        // we retrieve all <input> elements (this isn't strictly
        // necessary, since we have a reference outside of the
        // function and we could use that variable here, but
        // this is my preference as it allows for code to be
        // moved around:
        inputs = getAll('input'),
        
        // we check that every <input> is valid using the validityState
        // interface; if so the state is set to (Boolean) true,
        // otherwise it's set to false:
        state = inputs.every((el) => el.validity.valid);
      // here we invert the state (if all <input> elements are valid
      // we want the disabled state of the <button> to be false):
      button.disabled = !state;
    };
  // iterating over the <input> elements using Array.prototype.forEach():
  inputs.forEach(
    // arrow function passes the current <input> into the function
    // as the 'el' argument; here we use EventTarget.addEventListener()
    // to bind the checkValidity() function - note the deliberate lack
    // of parentheses - as the event-handler for the 'input' event:
    (el) => el.addEventListener('input', checkValidity)
  );
}
/* A simple reset, to remove default margin and padding,
   and to have element-sizes calculated by including
   border-sizes and padding in the declared width: */
*,::before,::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

form {
  /* using flex-box layout: */
  display: flex;
  /* flex-direction: row;
     flex-wrap: wrap; */
  flex-flow: row wrap;
  /* setting a gap of 0.5em between adjacent elements: */
  gap: 0.5em;
  /* margin - in left-to-right, top-to-bottom languages
     such as English - this is equivelent to margin-top
     and margin-bottom: */
  margin-block: 1em;
  /* margin - in left-to-right, top-to-bottom languages
     such as English - this is equivelent to margin-left
     and margin-right: */
  margin-inline: auto;
  /* setting a preferred width of 60vw, but preventing
     sizes smaller than 12em and limiting the maximum
     to 1000px at most; inline-size is equivalent to
     width (in English) */
  inline-size: clamp(12em, 60vw, 1000px);
}

label {
  /* vertically aligning the content  */
  align-items: center;
  /* setting the border style:
      border-width: 1px;
      border-style: solid;
      border-color: var(--color-validity);
     this last sets the color of the border
     to be equal to the CSS custom property:
    */
  border: 1px solid var(--color-validity);
  /* using flex-box layout on its contents: */
  display: flex;
  /* sizing the <label> to be 100% width: */
  flex-basis: 100%;
  /* setting its contents to
      flex-direction: row;
      flex-wrap: wrap;
     to allow those contents to be displayed in rows,
     and to be able to dynamically resize and wrap: */
  flex-flow: row wrap;
  /* allows the element to grow to occupy maximum space
     possible: */
  flex-grow: 1;
  gap: inherit;
  padding: 0.25em;
  /* using a transition of 0.3seconds on the scale
     property: */ 
  transition: scale 0.3s ease-in;
}

label:focus-within {
  /* increases the size of the element when the
     input descendant is focused: */
  scale: 1.1;
  /* the element will be scaled from its center
     point: */
  transform-origin: 50% 50%;
}

/* a <label> that has a :valid descendant will
   set the --color-validity property to lime: */
label:has(:valid) {
  --color-validity: lime;
}

/* a <label> that has an :invalid descendant will
   set the --color-validity property to red: */
label:has(:invalid) {
  --color-validity: red;
}

/* styling the placeholder of the <input> elements */
::placeholder {
  font-style: italic;
}

.titleText {
  flex-basis: 30%;
  flex-grow: 1;
  white-space: nowrap;
}

/* an element with the class of "titleText" within a
   <label> which has a descendant with the "required"
   attribute will have the content of '*' in its
   ::after pseudo-element, and that will be colored
   according the --color-validity custom-property: */
label:has([required]) .titleText::after {
  content: '*';
  color: var(--color-validity);
}

input {
  flex-basis: 50%;
  flex-grow: 1;
  padding: 0.25em;
}
<form action="#">
<label>
  <span >Enter character first name</span>
  <!-- to make use of HTML validation, both the 'required' attribute must be set and a pattern
       supplied; the 'pattern' attribute is a string containing a regular expression,
       below we have a regular expression to match:
        1. ^ starts at the beginning of the string,
        2. [A-Z] one upper-case letter in the range from A-Z inclusive, leading white-space
             is not considered valid,
        3. [a-zA-Z-] a letter of either upper or lower case between a-z, or a hyphen,
        4. {2,} repeated at least twice (but with no maximum),
        5. continuing until the end of the string (trailing white-space is not valid) -->
  <input type="text" placeholder="John, Lucy, Rashda..." pattern="^[A-Z][a-zA-Z-]{2,}$" required>
</label>
<label>
  <span >Enter character family name</span>
  <input type="text" placeholder="John, Lucy, Rashda..." pattern="^[a-zA-Z]'?[a-zA-Z]{2,}$" required>
</label>
<button type="submit">Submit</button>
</form>

JS Fiddle demo.

Note that while the CSS won't perform to style the <label> elements or their descendants, in browsers that don't support the :has() selector, the HTML validation of the <input> elements will still function if, for any reason, the JavaScript doesn't run.

References:

  • Related