Возможна ли HTML и JS валидация одновременно?

116
08 апреля 2022, 21:50

Стоит такая задача. Не спрашивайте ситуацию и зачем такой способ, просто в данном случае так надо.

Форма проходит валидацию html полей, их type.
JS выполняет мини-валидацию для кнопки отправки формы и сравнивает 2 поля. Надо, если 2 поля не равны, то не отправлять форму, но вывести ошибку валидации этой формы от html.

Я пробовал несколько вариантов:

  1. Сделал form.submit();, но это не подошло, потому что не выполнялась html валидация формы, а форма просто не отправлялась. То есть 50% нужного результата.
  2. Валидация полей проходила в Js, но даже если 2 поля отличаются, то js выдавал свою ошибку валидации, но всё равно отправлял форму.

Как можно сделать так, чтобы проходила JS и HTML валидация формы одновременно, но в случае ошибки в валидации JS, выводились результаты HTML валидации, но форма не отправлялась?

Надеюсь, не сильно запутал.
Спасибо!

Вот мой случай:

function validate() { 
  let a = document.forms["formId"]["name"].value; 
  if (a == "") { 
    return false; 
  } 
  let b = document.forms["formId"]["date"].value; 
  if (b == "") { 
    return false; 
  } 
  let c = document.forms["formId"]["dateend"].value; 
  if (c == "") { 
    return false; 
  } 
  if (new Date(b) >= new Date(c)) { 
    document.forms["formId"]["date"].style.backgroundColor = "rgba(250, 10, 10, 0.3)"; 
    document.forms["formId"]["dateend"].style.backgroundColor = "rgba(250, 10, 10, 0.3)"; 
    return false; 
  } else { 
    document.forms["formId"]["date"].style.backgroundColor = "rgba(130, 130, 255, 0.1)"; 
    document.forms["formId"]["dateend"].style.backgroundColor = "rgba(130, 130, 255, 0.1)"; 
  } 
  let d = document.forms["formId"]["description"].value; 
  if (d == "") { 
    return false; 
  } 
  return true; 
} 
 
function funBut() { 
  if (validate()) { 
    var onebutn = document.getElementById("onebutn"); 
    var twobutn = document.getElementById("twobutn"); 
    onebutn.style.display = "none"; 
    twobutn.style.display = "block"; 
  } 
}
<form id="formId" name="upload" action="scripts/generator.php" target="_blank" method="POST" ENCTYPE="multipart/form-data"> 
  <div> 
    <div style="width:auto;"> 
      <label for="email">Имя</label> 
      <input type="text" id="name" name="name" maxlength="200" required /> 
    </div> 
    <div class="form-group"> 
      <label for="date">Дата начала</label> 
      <input type="datetime-local" min="2020-01-01T00:00" max="5000-01-01T00:00" id="date" name="date" onChange="document.getElementById('dateend').min=this.value" required /> 
    </div> 
    <div class="form-group"> 
      <label for="dateend">Дата окончания</label> 
      <input type="datetime-local" min="2020-01-01T00:00" max="5000-01-01T00:00" id="dateend" name="dateend" style="color: white;" required /> 
    </div> 
    <div class="form-group" style="width:auto;"> 
      <label for="description">Комментарий</label> 
      <textarea id="description" name="description" maxlength="1500" required></textarea> 
    </div> 
    <div id="twobutn" style="display:none;"> 
      <div class="form-group" id="bch"> 
        <input type="submit" id="check" name="check" style="color: white;" value="Проверить" onClick="document.upload.action='scripts/generator.php'; return true;"> 
      </div> 
      <div class="form-group" id="bby" style="width:auto;"> 
        <input type="submit" class='open-modal' id="create" name="create" value="Создать мероприятие"> 
      </div> 
    </div> 
    <div id="onebutn" class="form-group" style="width:auto;"> 
      <input type="submit" id="check" name="check" style="color: white;" value="Проверить" onClick="funBut(); document.upload.action='scripts/generator.php'; return true;"> 
    </div> 
  </div> 
</form>

Answer 1
Как с помощью JavaScript блокировать отправку формы?
  • <form onsubmit="return false" >
    внутри onsubmit вернуть false
  • <form onsubmit="return validate(this)" >
    или вызвать функцию, которая вернёт false

/** @param {HTMLFormElement} el */ 
function validate(el = document.forms['Ffq']) { 
    const { text, start, end } = validate.getVars(el) 
    // -,- 
    // console.log({ text, start, end }) 
    const isOK = [ 
        , !!text// можно убрать, т.к. `<input required>` 
        , (new Date(start) <= new Date(end)) 
    ].every(q => true === q) 
    if (isOK) return true; 
    else return false; 
} 
/** @param {HTMLFormElement} el */ 
validate.getVars = function getVars(el) { 
    const { value: text } = el['text']; 
    const { value: start } = el['start']; 
    const { value: end } = el['end']; 
    // -,- 
    return { text, start, end, } 
}
<script> 
  // ----> перехватчик исключительно для демонстрации работы кода 
  window.addEventListener('beforeunload', e => { 
    // - ,- catch 
    e.preventDefault() 
    e.stopPropagation() 
    // -, - 
    console.group('beforeunload') 
    formData = new FormData(document.forms['Ffq']); 
    console.dir(JSON.stringify([...formData])) 
    console.groupEnd() 
  }) 
  // <---- 
</script> 
<form name="Ffq" method="post" action="https://localhost" onsubmit="return validate(this)"> 
  <input type="submit" value="search" /> 
  <input type="text" name="text" required> 
  <input type="date" name="start"> 
  <input type="date" name="end"> 
</form>

список "полезной литературы"

  • HTML тег <form> - http://htmlbook.ru/html/form
  • отправка формы средствами JavaScript - https://learn.javascript.ru/xhr-forms
  • FormData - https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData
  • document.forms - https://developer.mozilla.org/en-US/docs/Web/API/Document/forms
Answer 2

что же касается кода, приведённого автором вопроса:

переработанный JS + теория из предыдущего(общего) ответа

обоснования своих изысканий с доказательством на примере кода автора вопроса

function funBut() { 
    const isValid = validate() 
    if (isValid) { 
        document.getElementById("onebutn").style.display = "none"; 
        document.getElementById("twobutn").style.display = "block"; 
    } 
    // console.log({ isValid }) 
    return isValid 
} 
/** @param {HTMLFormElement} _formId */ 
function validate(_formId = document.forms['formId']) { 
    /** @type {HTMLInputElement[]} */ 
    const els = ['name', 'date', 'dateend', 'description'].map(q => _formId[q]) 
    const [_name, _date, _dateend, _description] = els 
    const [a, b, c, d] = els.map(el => el.value) 
    // -,- 
    const dd = (new Date(b) >= new Date(c)) 
    // -,- 
    if (dd) [_date, _dateend].forEach(validate.styleErr) 
    else[_date, _dateend].forEach(validate.styleOk) 
    if ([a, b, c, d].every(q => "" != q) && dd) return false; 
    return true; 
} 
validate.styleErr = style({ backgroundColor: 'rgba(250, 10, 10, 0.3)' }) 
validate.styleOk = style({ backgroundColor: 'rgba(130, 130, 255, 0.1)' }) 
/** @param {CSSStyleDeclaration} style */ 
function style(style) { 
    /** @param {HTMLElement} el */ 
    const f = el => { Object.assign(el.style, style) } 
    return f 
}
<script>// ---- > перехватчик исключительно для демонстрации работы кода 
window.addEventListener("beforeunload",o=>{o.preventDefault(),o.stopPropagation(),console.group("beforeunload"),formData=new FormData(document.forms.formId),console.dir(JSON.stringify([...formData])),console.groupEnd()}); 
// <----</script> 
 
<hr> 
2020-01-01T00:00<br> 
5000-01-01T00:00<br> 
<hr> 
 
<form id="formId" name="upload" action="http://localhost" method="POST" ENCTYPE="multipart/form-data" onsubmit="return funBut();"> 
  <div> 
    <div style="width:auto;"> 
      <label for="email">Имя</label> 
      <input type="text" id="name" name="name" maxlength="200" required value="имя" /> 
    </div> 
    <div class="form-group"> 
      <label for="date">Дата начала</label> 
      <input type="datetime-local" min="2020-01-01T00:00" max="5000-01-01T00:00" id="date" name="date" onChange="document.getElementById('dateend').min=this.value" required value="2020-01-01T00:00" /> 
    </div> 
    <div class="form-group"> 
      <label for="dateend">Дата окончания</label> 
      <input type="datetime-local" min="2020-01-01T00:00" max="5000-01-01T00:00" id="dateend" name="dateend" style="color: white;" required value="5000-01-01T00:00" /> 
    </div> 
    <div class="form-group" style="width:auto;"> 
      <label for="description">Комментарий</label> 
      <textarea id="description" name="description" maxlength="1500" required>коммент</textarea> 
    </div> 
    <div id="twobutn" style="display:none;"> 
      <div class="form-group" id="bch"> 
        <input type="button" id="check" name="check" style="color: white;" value="Проверить 2" onclick="funBut();"> 
      </div> 
      <div class="form-group" id="bby" style="width:auto;"> 
        <input type="submit" class='open-modal' id="create" name="create" value="Создать мероприятие"> 
      </div> 
    </div> 
    <div id="onebutn" class="form-group" style="width:auto;"> 
      <input type="button" id="check" name="check" style="color: white;" value="Проверить 1" onclick="funBut(); "> 
    </div> 
  </div> 
</form>

комментарии/замечания

onClick

похоже на реакт. style же - строчный. хмм.

я не утверждаю, просто оставлю это тут:

  • https://validator.w3.org/

<input type="submit"/>

Должен быть один. Отстальные - <input type="button"/>

Добавим к ним по проверке-подсветке-экшнпереключалке onclick="funBut();"

<form onsubmit="return funBut();">

Это ключевая часть, отвечает за то - будет ли отправлена форма или нет. (см. предыдущий ответ)

использование различного синтаксиса

в одном месте используется document.upload
в другом - document.forms['formId']

READ ALSO
Как обернуть каждое изображение в отдельный блок?

Как обернуть каждое изображение в отдельный блок?

Возникла проблема так как я не верно что то делаюЯ хочу обернуть каждое изображение в div с любым именем class

118
Отправка по нажатию

Отправка по нажатию

У меня есть часть кода которая при закрытии окна сразу выполняет код

238
Vue JS &amp; Google maps. Директивы рендерятся как HTML теги

Vue JS & Google maps. Директивы рендерятся как HTML теги

Использую библиотеку 2vue-google-maps для VueВ infoWindow есть кнопка с @click, проблема в том что она рендерится как обычный HTML тег и собственно не работает

215