Skip to content

[ ADD ON ] form validator

Shape group edited this page Mar 28, 2020 · 5 revisions

░░ VALIDATION FORMS

This script is useful for understanding how to validate a form (or more than one) in a page created with the framework.

Basically it is similar to any validator but it integrates perfectly with the available ui.

now ... it is not essential to understand everything but it is necessary to understand some key points:

  • the script cycles through all the forms

  • where it finds the "required" attribute enters and checks the values

  • if a pattern exists it will respect that pattern, otherwise it will assign a standard. If it does not exist ... it will not take into consideration the parameter. The control pattern can be given via the common html, the automatic one via a special "data-autopattern" attribute (it is true by default)

  • the most complicated is certainly the control on the dates... let's try to understand it. attributes are evaluated only if they exist.
    You have several classes to put on the input field for more detailed checks:

  • check[onlythisyear] -> check if the date is from the current year;

  • check[underage] -> check if the age is legally acceptable (here in Italy it is 18, in the USA it is 21 ... you can easily change it in the script)

  • check[dateprenotation] -> is the most advanced control. Check the standard, the min-max, and a range of enabling period.

    • range of enabling period note: the period range is an addition. It is needed in those cases where there is the possibility, for example, to book only in a specific date range, leaving min and max to evaluate the daily range.
       
      For example:
      Range = "early summer, late summer"
      Min and max = check if the day is antecendete or leave at least 24 hours before booking (or otherwise, it is up to you to edit the script)
       
      In this regard there is an addition to the class of this validator that allows you to recover the current day and add or remove based on your needs. In this way you will be able to determine a minimum range of 24 hours (this day + 1) and the maximum general corrections.

Important note: Being under construction some things may be missing or need to be removed. For example, the control on the radio buttons is not complete. Remember that.

to conclude: once the loop of the fields is finished, the script will estimate which are the main messages - without repeating them for each element - to bring to the user's attention. They will be printed in the appropriate element (you can configure its style like any other of the framework) which MUST BE IN THE FORM.

The script:



  // k validator > https://git.io/JvQsK

  class validator
  {

    constructor()
    {
      this.checkform();
    }

    checkform()
    {
    
      let Forms = document.getElementsByTagName('FORM');
    
      if(Forms.length>=0)
      {
    
        let Fl = Forms.length;
        for (let f = 0; f < Fl; f++)
        {
    

          // get elements nside that form

          let FormElemets = Forms[f].querySelectorAll('[required]'),
              send = Forms[f].querySelectorAll('[type="submit"]')[0],
              alarmbox = Forms[f].querySelectorAll(Forms[f].tagName+' .alarmbox')[0],
              alarmdisplay = alarmbox.querySelectorAll('.alarm-display')[0],
              fields = [],     // storized type of bad field (is it input text?)
              alarmtext = {},     // storized message for bad field (if it's text and fields text exist... then write the message.)
              isFormvalid = false;
    
    

          if(FormElemets.length>=0)
          {
    
    
            // make required - add icon

            let fel= FormElemets.length;
            for (let i = 0; i < fel; i++)
            {
              let requirer = document.createElement('b');
              requirer.classList.add('required');
              FormElemets[i].parentNode.insertBefore(requirer, FormElemets[i]);
            }
    
    
            //activation

            Forms[f].addEventListener("click", ()=>{ check(event); } );
    

            //check it

            function check(event)
            {

              // if exist, reset the list of fields
              fields.length = 0;

  
              // loop all "required" fields in form
              let fel= FormElemets.length;
              for (let i = 0; i < fel; i++)
              {
    

                // get the field 
                let El = FormElemets[i],
                    hasattribute,
                    pattern,
                    originalpattern,
                    textholder =  El.getAttribute('placeholder'),
                    val = El.getAttribute('value'),
                    type = El.getAttribute('type'),
                    isvalid;
    
    
    
                // some elements getted value from object and not attribute
                val&&null!=val&&null!=val||(val=El.value);

    
                // attribute exixst
                if(El.hasAttribute('pattern') || El.hasAttribute('data-autopattern'))
                { 
                  hasattribute = true;
                  originalpattern = El.getAttribute('pattern');
                  pattern = new RegExp(originalpattern);
                }
    

                /// TEXT > check all inputs whit attribute "pattern":  
                if ( type == 'text' )
                {
                  if(hasattribute)
                  {
                    if(!originalpattern)
                    { pattern = new RegExp("^(?=.*[a-zA-Z0-9 ]).{3,25}$"); }
    
                    if(!pattern.test(val))
                    { isvalid=false; alarmtext.text = 'error: you can only use simple letters, numbers and symbols in text fields.'; }
                    else
                    { isvalid=true;  }
                  }
                  else
                  { if(!val || val == "" || val == textholder) isvalid=false; else isvalid= true; }
                }
    

                /// PASSWORD
                else if(  type == 'password' )
                {

                  if(hasattribute)
                  {

                    if(!originalpattern)
                    { pattern = new RegExp("^(?=.*[a-zA-Z0-9#$_^+=!*()@%&]).{8,12}$"); }

                    if(!pattern.test(val))
                    { isvalid=false;  alarmtext.password = 'error: incorrect characters on the password. 8-12 characters and at least one number and one symbol.'; }

                    else
                    { isvalid=true; }

                  }
                  else
                  { if(!val || val == "" || val == textholder) isvalid=false; else isvalid= true; }

                }


                /// NUMBER & TEL
                else if ( type == 'number' ||  type == 'tel'  )
                {

                  if(hasattribute)
                  {

                    if(!originalpattern)
                    { pattern =/^[0-9]+$/; }
    
                    if(!pattern.test(val))
                    { isvalid=false;  alarmtext.number = 'error: incorrect numeric fields.'; alarmtext.tel = 'error: incorrect phone fields.'; }
                    else
                    { isvalid=true; }

                  }
                  else
                  { if(!val || val == "" || val == textholder) isvalid=false; else isvalid= true; }

                }


                /// EMAIL
                else if ( type == 'email' )
                {

                  if(hasattribute)
                  {

                    if(!originalpattern)
                    { pattern = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/; }
    
                    if( !pattern.test(val) || !val.match('@') && !val.match('.') )
                    { isvalid=false; fields.email = false; alarmtext.email = 'error: incorrect email fields.'; }
                    else
                    { isvalid=true; }

                  }
                  else
                  { if(!val || val == "" || val == textholder) isvalid=false; else isvalid= true; }

                }


                /// URL
                else if ( type == 'url' )
                {

                  if(hasattribute)
                  {

                    if(!originalpattern)
                    { pattern = new RegExp("^(http[s]?:\\/\\/(www\\.)?|ftp:\\/\\/(www\\.)?|www\\.){1}([0-9A-Za-z-\\.@:%_\+~#=]+)+((\\.[a-zA-Z]{2,3})+)(/(.)*)?(\\?(.)*)?") }
    
                    if(!pattern.test(val))
                    { isvalid=false; alarmtext.url = 'error: you entered an invalid url.'; }
                    else
                    { isvalid=true; }

                  }
                  else
                  { if(!val || val == "" || val == textholder) isvalid=false; else isvalid= true; }

                }
    
    
                /// TEXTAREA
                else if( El.tagName.toLowerCase() == 'textarea')
                {
    
                  type = 'textarea';
    
                  if(hasattribute)
                  {

                    if(!originalpattern)
                    { pattern = new RegExp("^(?=.*[a-zA-Z0-9#$_^+=!*()@%&<>/ ]).{10,350}$"); }
    
                    if(!pattern.test(val) || !val || val == textholder)
                    { isvalid=false; alarmtext.textarea = 'error: description field wrong. 10 to 350 characters. Only letters, numbers and basic symbols.'; }
                    else
                    { isvalid=true;  }

                  }
                  else
                  { if(!val || val == "" || val == textholder) isvalid=false; else isvalid= true; }
    
                }
    
    
                /// CHECKBOX
                else if( type == 'checkbox' )
                {

                  if(El.checked == false)
                  { isvalid=false; alarmtext.checkbox = 'error: it seems that some ticks are incorrect or missing.'; }
                  else
                  { isvalid=true; }

                }
    
                /// RADIO
                else if( type == 'radio' )
                {

                  if(El.checked == false)
                  { isvalid=false; alarmtext.radiobox = 'error: it seems that some ticks are incorrect or missing.'; }
                  else
                  { isvalid=true;  }
    
                  // Under costruction
                  // che all name of radio, for all name...
                  // let Radios = E.closest('FORM').querySelectorAll()
                  // for (let i = 0; i < r.length; i++) {
                  //   array[i]
                  // }

                }
    
                /// DATE
                else if( type == 'date' )
                {
    
                  
                  let isunderagecheck; isunderagecheck=!!El.classList.contains("check[underage]");                  // major people year
                  let isonlythisyear; isonlythisyear=!!El.classList.contains("check[onlythisyear]");                // only this year
                  let isprenotationcheck; isprenotationcheck=!!El.classList.contains("check[dateprenotation]");     // prenotation
    
    
                  let //get all type of variants data
                      date = new Date(),                                      // init of date
                      thisyear = parseInt(date.getFullYear()),                // get this yead
                      valToD = String(val.split("/")[2]),                     // day selected in the field
                      valToM = String(val.split("/")[1]),                     // months selected in the field
                      valToY = String(val.split("/")[0]),                     // year selected in the field
                      valDate = Date.parse( valToY+'/'+valToM+'/'+valToD ),   // transormed utc data selected n the field 
                      min = El.getAttribute('min'),                           // get min day date
                      max = El.getAttribute('max'),                           // get max day date
                      periodstart = null,                                     // create a start of period range (or ex "start summer season": Date.parse(valToY+'/06/01') , alt: El.getAttribute('data-rangestart'))
                      periodend = null;                                       // create a end of period range (or ex "start summer season": Date.parse(valToY+'/09/15') , alt: El.getAttribute('data-rangeend')) 
    
  
                  // checks ege
                  if(isunderagecheck)
                  {
    
                    if(val == textholder )
                    { isvalid = false;  alarmtext.date = 'error on dates: missing date.';  }
                    else
                    {
    
                      let minimumEge = thisyear-18,   //from this yead -18 = minimum day for major ege
                          overoldEge = thisyear-100;  //are you dead?? :\
    
                      if(valToY>=minimumEge)
                      { isvalid = false;  alarmtext.date = 'error on dates: WARNING! You must be of age! Call your parents and get help.'; }

                      else if(valToY<=minimumEge && valToY<=overoldEge)
                      { isvalid = false;  alarmtext.date = 'error on dates: Are you over 100 years old? possible? Double check your dates!'; }

                      else
                      { isvalid = true;}
    
                    }
    
                  }
                  
                  else if( isonlythisyear && valToY != thisyear )
                  { isvalid = false; alarmtext.date = "error on dates: Sorry, you can only book during the current year."; }
    
                  //check for complex prenotations
                  else if(isprenotationcheck)
                  {
    
                    if(val == textholder )
                    { isvalid = false;  alarmtext.date = 'error: missing date.';  }
                    else
                    {
    
                      if ( (periodstart != null && periodend != null) && (valDate < periodstart || valDate > periodend) )
                      { isvalid = false; alarmtext.date = "error on dates: Sorry, only dates from "+ periodstart +" and "+ periodend +" are valid. All other dates are not available.";  }
                      else
                      {
    
                        if( isonlythisyear && valToY != thisyear )
                        { isvalid = false; alarmtext.date = "error on dates: Sorry, you can only book during the current year."; }
                        else
                        {
    
                          if( (min && max) && (valDate<min || valDate>max))
                          { isvalid = false;  alarmtext.date = 'error on dates: Too tight times! Please select a day longer than today.'; }
                          else
                          {
                            isvalid = true;
                          }
    
                        }
    
                      }
    
                    }
    
                  }
    
                  else
                  {

                    if(val == textholder )
                    { isvalid = false;  alarmtext.date = 'Error, missing date.';  }
                    else
                    {

                      if( (min && valDate<min) && (max && valDate>max))
                      { isvalid = false;  alarmtext.date = 'Tempi troppo stretti! Seleziona un giorno maggiore di quello di oggi.'; }
                      else
                      {
                        isvalid = true;
                      }

                    }

                  }
    
                }
    
    
                /// Select
                else if(El.tagName.toLowerCase() == "select")
                {

                  type = 'select';
                  val = El.parentNode.getElementsByTagName('p')[0].innerText;

                  if(val == textholder || El.getAttribute('value') ==textholder)
                  { isvalid = false; alarmtext.select = 'error select: errors found in the selection and choice fields.'; }
                  else
                  { isvalid = true; }

                }
    
    

                // set view result and array
                if(isvalid==false)
                {
    
                  fields.push({ 
                    type:type,
                    valy:isvalid,
                    message:alarmtext[type]
                  });

                  El.closest("[class*='button']").classList.remove('border-pass');
                  El.closest("[class*='button']").classList.add('border-error');

                }
                else if(isvalid==true)
                {

                  fields.push({ 
                    type:type,
                    valy:isvalid,
                    message:''
                  });

                  El.closest("[class*='button']").classList.remove('border-error');
                  El.closest("[class*='button']").classList.add('border-pass');

                }
    
    
                // if loop ended
                if(i==(fel-1))
                {
    
    
                  //loop all field value. If even one is false, form is false!
                  isFormvalid = true;
                  for (let field in fields)
                  {
                    if(fields.hasOwnProperty(field))
                    {
                      if(fields[field].valy==false){isFormvalid=false;}
                    }
                  }
    
    
                  // print result and output:
    
                  if(isFormvalid == false)
                  {
    
                    event.stopPropagation();
                    send.closest("[class*='button']").classList.add('disabled','bkg-alert');
                    send.closest("[class*='button']").style.boxShadow="none";
                    send.closest("[class*='button']").disabled = true;
    
    
                    // loop all alarm label message and message in fileds, if that alarm label is present in the fields messages... print the alarm, else not.
                    let htmlcode = ``;
                    for (let alarm in alarmtext)
                    {
    
                      let keyexist=false;
                      for (let field in fields)
                      {
                        if(fields[field].message == alarmtext[alarm])
                        {
                          keyexist = true;
                        }
                      }
    
                      if(keyexist==true)
                      {
                        htmlcode += `<p>`+`${alarmtext[alarm]}`+`</p>`;
                      }
    
                    }
    
                    alarmdisplay.innerHTML=htmlcode;
    
                    alarmbox.classList.add('active');
                    alarmbox.classList.remove('off');
    
                  }
                  else
                  {
                    send.closest("[class*='button']").classList.remove('disabled','bkg-alert');
                    send.closest("[class*='button']").disabled = false;
                    alarmbox.classList.add('off');
                    alarmbox.classList.remove('active');
                  }
    
    
    
                }
    
              }
    
            }
    
          }
    
        }
    
      }
    
    }

  };

  window.addEventListener("load", ()=>{ 
    var formvalidator = new validator();
  }, false);
  

exemple of html form:

<form>

  <div class="button-text">
    <input type="text" name="" value="" placeholder="this is a test" data-autopattern required/>
  </div>

  <div class="space-05"></div>

  <div class="button-text">
    <input type="email" name="" value="" placeholder="[email protected]" data-autopattern required/>
  </div>
  
  <div class="space-05"></div>
  
  <div class="button-text">
    <input type="password" name="" value="" placeholder="password" data-autopattern required/>
  </div>

  <div class="space-05"></div>

  <div class="button-text">
     <input type="url" placeholder="www.yoursite.com" data-autopattern required/>
  </div>

  <div class="space-05"></div>

  <div class="button-text">
     <input type="tel" placeholder="00000000000" data-autopattern required/>
  </div>

  <div class="space-05"></div>

  <div class="button-text">
     <textarea placeholder="a simple textarea" data-autopattern required>a simple textarea</textarea>
  </div>

  <div class="space-05"></div>

  <p class="font-size-8-tone-2">classic check</p>
  <div class="button-date EUR DMY">
      <p>Calendar...</p>
      <input type="date" value="Calendar..." placeholder="Calendar..." required/>
  </div>

  <div class="space-05"></div>

  <p class="font-size-8-tone-2">check only this year</p>
  <div class="button-date EUR DMY">
      <p>select a date</p>
      <input class="check[onlythisyear]" type="date" value="select a date" placeholder="select a date"  required/>
  </div>

  <div class="space-05"></div>

  <p class="font-size-8-tone-2">check under age</p>
  <div class="button-date EUR DMY">
      <p>Your age</p>
      <input class="check[underage]" type="date" value="Your age" placeholder="Your age"  required/>
  </div>

  <div class="space-05"></div>

  <p class="font-size-8-tone-2">prenotation check</p>
  <div class="button-group">
    
    <div class="button-date EUR DMY ">
        <p>From...</p>
        <input class="check[dateprenotation]" type="date" value="From..." placeholder="From..." required/>
    </div>
    <div class="button-date EUR DMY prenotation">
        <p>To...</p>
        <input class="check[dateprenotation]" type="date" value="To..." placeholder="To..." required/>
     </div>

 </div>

  <div class="space-05"></div>

  <div class="button-number">
     <span> <p>-</p> <span>
     <span> <p>+</p> <span>
     <div></div>
     <input type="number" min="-100" max="100" value="0" readonly required/>
  </div>

  <div class="space-10"></div>

  <div class="alarmbox off">
    <div class="alarm-display bkg-alert radius-small font-small font-tone-1 space-15 align-left">
    </div>
    <div class="space-10"></div>
  </div>
  
  <div class="button-action">
    <input type="submit" name="" value="TRY NOW"/>
  </div>

</form>

How to automatically recover today's date for min and max

As mentioned above, when checking dates, it will often be necessary to change the min and max for a short-term check.

The problem is that, having reached this level, it is necessary to do it dynamically.

"What day is it? Add 1 to give customers time to get organized"

or:

"What day is it? Is it before today? Then you can't!"

How to do? We built an expansion of the validator. addition to the previous script (before that of the validator!)

Here is the addition:

  class validator
  {

    constructor()
    {
      this.getMinMaxDay();
      this.checkform();
    }

    getMinMaxDay()
    {
    
      let El = [...document.querySelectorAll('input[type="date"]')],
          elfinded = El.length,
          todayDate = new Date(),
          thisyear = todayDate.getFullYear();
    
      for (let i = 0; i < elfinded; i++)
      {
    
        let attrs = El[i].attributes,
            attrsleng = attrs.length;
    
        for (let i = 0; i < attrsleng; i++)
        {
    
          let attr = attrs[i];
    
          if(attr.value=='getMinDay')
          {
    
            // original
            // let dd = String(todayDate.getDate()+1).padStart(2, '0'),
            //     mm = String(todayDate.getMonth()).padStart(2, '0'),
            //     tomorrow = Date.parse(thisyear+'/'+mm+'/'+dd); 
    
              let dd = String(todayDate.getDate()+1).padStart(2, '0'),
                  mm = String(todayDate.getMonth()).padStart(2, '0');
    
              if(parseInt(mm)<4){ mm="04"; dd="01"; }
              else if(parseInt(mm)>9){ mm="09"; dd="14"; }
    
              let tomorrow = Date.parse(thisyear+'/'+mm+'/'+dd); 
    
            attr.value = tomorrow;
          }
          else if(attr.value=='getMaxDay')
          {
            let summerclose = Date.parse(thisyear+'/09/14');  // in this app summer end to september
            attr.value = summerclose;
          }
    
        }
    
      }
    
    }

    checkform()
    {
        ...
    }

how to set the html:

<form>

    <div class="button-date EUR DMY">
        <p>Calendar...</p>
        <input type="date" value="Calendar..." min="getMinDay" max="getMaxDay"/>
    </div>

</form>
Clone this wiki locally