question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

isValid throwing false to valid inputs and error messages incomplete

See original GitHub issue

I am doing a devise registration multi-step using stimulus and following part of https://github.com/DavyJonesLocker/client_side_validations-simple_form/wiki/Validations-with-simple_form-Twitter-Bootstrap-integration but I did some changes because wasn’t working properly:

let valid = true;
$('input:visible, select:visible').each(function() {
  const settings = window[this.form.id].ClientSideValidations.settings;
  if (!$(this).isValid(settings.validators)) {
    valid = false
  }
});
if (valid) {
  //code to go to next step
  if (e.currentTarget.id === "nextBtn") this.index++;
}

Steps to reproduce

First bug (isValid throwing false): Get redirect to registration page by a link. Then I tried to trigger validation unfocusing from input or clicking in next btn. Works normally if I refresh the page. Second bug (Error message incomplete): unfocus inputs to trigger validation throught gem

Expected behavior

First bug: To email input focus normally. Unfocus at input should trigger validations to show up errors messages in case have any. Click at next button should too trigger validations and shows errors messages or, in case of all inputs are valid, go to the next tab. Second bug: The errors messages include also the input type like “Email can’t be blank”

Actual behavior

First bug: Unfocus and click on next btn didn’t trigger anything. I tried debug and it seems like $(this).isValid(settings.validators) always throw false, even if I fill all inputs with valid values. It didn’t shows up any errors messages too. Second bug: Error message shows up like “can’t be blank”.

System configuration*

Rails version: 6.0.3.4

Ruby version: 2.6.6

Client Side Validations version: 17.1.0

Client Side Validations Simple Form version: 11.1.0

Bootstrap version (if used): 4.5.3

Code snippet from your model of the validations*

devise validation and validates :role, presence: true

Relevant part of application.js

require('@client-side-validations/client-side-validations') require('@client-side-validations/simple-form/dist/simple-form.bootstrap4') it’s after turbolinks.start()

The whole form code from your template

<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), validate: true, data: { controller: "form" }) do |f| %>
    <%= f.error_notification %>

    <div class="tab" data-target="form.tab">
      <%= f.input :email,
                  required: true,
                  autofocus: true,
                  input_html: { autocomplete: "email" },
                  validate: true %>
      <%= f.input :password,
                  required: true,
                  hint: ("#{@minimum_password_length} characters minimum" if @minimum_password_length),
                  input_html: { autocomplete: "new-password" },
                  validate: true %>
      <%= f.input :password_confirmation,
                  required: true,
                  input_html: { autocomplete: "new-password" } %>
    </div>

    <div class="tab" data-target="form.tab">
      <%= f.input :role, collection: %w[pj manager],
                  validate: true %>
    </div>

    <div class="form-actions">
      <button class="btn-orange" type="button" id="prevBtn" data-action="form#nextPrev" data-target="form.prevBtn">Previous</button>
      <button class="btn-orange" type="button" id="nextBtn" data-action="form#nextPrev" data-target="form.nextBtn">Next</button>
    </div>
  <% end %>

The resulting HTML*

    <form class="simple_form new_user" id="new_user" novalidate="novalidate" data-controller="form" data-client-side-validations="{&quot;html_settings&quot;:{&quot;type&quot;:&quot;SimpleForm::FormBuilder&quot;,&quot;error_class&quot;:&quot;invalid-feedback&quot;,&quot;error_tag&quot;:&quot;div&quot;,&quot;wrapper_error_class&quot;:&quot;form-group-invalid&quot;,&quot;wrapper_tag&quot;:&quot;div&quot;,&quot;wrapper_class&quot;:&quot;form-group&quot;,&quot;wrapper&quot;:&quot;vertical_form&quot;},&quot;number_format&quot;:{&quot;separator&quot;:&quot;.&quot;,&quot;delimiter&quot;:&quot;,&quot;},&quot;validators&quot;:{&quot;user[email]&quot;:{&quot;presence&quot;:[{&quot;message&quot;:&quot;can't be blank&quot;}],&quot;uniqueness&quot;:[{&quot;message&quot;:&quot;has already been taken&quot;,&quot;case_sensitive&quot;:true,&quot;allow_blank&quot;:true}],&quot;format&quot;:[{&quot;message&quot;:&quot;is invalid&quot;,&quot;with&quot;:{&quot;source&quot;:&quot;^[^@\\s]+@[^@\\s]+$&quot;,&quot;options&quot;:&quot;&quot;},&quot;allow_blank&quot;:true}]},&quot;user[password]&quot;:{&quot;presence&quot;:[{&quot;message&quot;:&quot;can't be blank&quot;}],&quot;confirmation&quot;:[{&quot;message&quot;:&quot;doesn't match Password&quot;,&quot;case_sensitive&quot;:true}],&quot;length&quot;:[{&quot;messages&quot;:{&quot;minimum&quot;:&quot;is too short (minimum is 6 characters)&quot;,&quot;maximum&quot;:&quot;is too long (maximum is 128 characters)&quot;},&quot;allow_blank&quot;:true,&quot;minimum&quot;:6,&quot;maximum&quot;:128}]},&quot;user[role]&quot;:{&quot;presence&quot;:[{&quot;message&quot;:&quot;can't be blank&quot;}]}}}" action="/users" accept-charset="UTF-8" method="post"><input type="hidden" name="authenticity_token" value="ccfkjL7QIt6kcFNVkn0Emu5bdXnt+DXVieim/YbPBXHiywdNiPE1u5qjyohRyK3MplNwyhJtG4T+I9ts9WGasQ==">
    

  <div class="tab current-tab" data-target="form.tab">
      <div class="form-group email required user_email"><label class="email required" for="user_email">Email <abbr title="required">*</abbr></label><input class="form-control string email required" autocomplete="email" autofocus="autofocus" required="required" aria-required="true" type="email" value="" name="user[email]" id="user_email"></div>
      <div class="form-group password required user_password"><label class="password required" for="user_password">Password <abbr title="required">*</abbr></label><input class="form-control password required" autocomplete="new-password" required="required" aria-required="true" type="password" name="user[password]" id="user_password"><small class="form-text text-muted">6 characters minimum</small></div>
      <div class="form-group password required user_password_confirmation"><label class="password required" for="user_password_confirmation">Password confirmation <abbr title="required">*</abbr></label><input class="form-control password required" autocomplete="new-password" required="required" aria-required="true" type="password" name="user[password_confirmation]" id="user_password_confirmation"></div>
    </div>

    <div class="tab" data-target="form.tab">
      <div class="form-group select required user_role"><label class="select required" for="user_role">Role <abbr title="required">*</abbr></label>
            <select class="form-control select required" name="user[role]" id="user_role">
            <option value=""></option>
            <option value="pj">pj</option>
            <option value="manager">manager</option>
            </select>
      </div>
    </div>
    <div class="form-actions">
      <button class="btn-orange" type="button" id="prevBtn" data-action="form#nextPrev" data-target="form.prevBtn" style="display: none;">Previous</button>
      <button class="btn-orange" type="button" id="nextBtn" data-action="form#nextPrev" data-target="form.nextBtn">Next</button>
    </div>
  </form>

Browser’s development console output*

  • [X ] I confirm that my browser’s development console output does not contain errors

Additional JavaScript Libraries*

Using JS framework Stimulus

Repository demostrating the issue

Debugging CSV issues is a time consuming task. If you want to speed up things, please provide a link to a repository showing the issue.


* Failure to include this requirement may result in the issue being closed.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
taglialacommented, Nov 5, 2020

Sorry, this is not possible out of the box

Feel free to request it as a feature in the main repo at https://github.com/DavyJonesLocker/client_side_validations-simple, but I will label as help-wanted because I do not have resources to implement it

You can customize error rendering by following this guide: https://github.com/DavyJonesLocker/client_side_validations#customize-error-rendering

For your specific use case, I think this will work:

import $ from 'jquery'
import ClientSideValidations from '@client-side-validations/client-side-validations'

ClientSideValidations.formBuilders['SimpleForm::FormBuilder'] = {
  add: function (element, settings, message) {
    this.wrapper(settings.wrapper).add.call(this, element, settings, message)
  },
  remove: function (element, settings) {
    this.wrapper(settings.wrapper).remove.call(this, element, settings)
  },
  wrapper: function (name) {
    return this.wrappers[name] || this.wrappers.default
  },

  wrappers: {
    default: {
      add (element, settings, message) {
        const wrapperElement = element.parent()
        let errorElement = wrapperElement.find(settings.error_tag + '.invalid-feedback')

        if (!errorElement.length) {
          errorElement = $('<' + settings.error_tag + '>', { class: 'invalid-feedback', text: message })
          wrapperElement.append(errorElement)
        }

        wrapperElement.addClass(settings.wrapper_error_class)
        element.addClass('is-invalid')
        errorElement.text(`${wrapperElement.find('label').clone().children().remove().end().text()} ${message}`)
      },

      remove (element, settings) {
        const wrapperElement = element.parent()
        const errorElement = wrapperElement.find(settings.error_tag + '.invalid-feedback')

        wrapperElement.removeClass(settings.wrapper_error_class)
        element.removeClass('is-invalid')
        errorElement.remove()
      }
    }
  }
}

Note the changed line from the original file at https://github.com/DavyJonesLocker/client_side_validations-simple_form/blob/master/src/main.bootstrap4.js:

errorElement.text(`${wrapperElement.find('label').clone().children().remove().end().text()} ${message}`)
1reaction
taglialacommented, Oct 28, 2020

@isaporto thanks.

Much easier to replicate and debug.

The issue depends on dynamically added fields that are activated when showCurrentTab javascript is executed

Ref: https://github.com/DavyJonesLocker/client_side_validations/wiki/Validating-dynamically-added-forms

diff --git a/app/javascript/controllers/form_controller.js b/app/javascript/controllers/form_controller.js
index 2370d75..efb4668 100644
--- a/app/javascript/controllers/form_controller.js
+++ b/app/javascript/controllers/form_controller.js
@@ -11,7 +11,7 @@ export default class extends Controller {
   nextPrev(e) {
     // if the form is valid then go to the next tab else don't
     let valid = true;
-    $('input:visible, select:visible').each(function() {
+    $('[data-validate]:input:visible').each(function() {
       const settings = window[this.form.id].ClientSideValidations.settings;
       if (!$(this).isValid(settings.validators)) {
         valid = false
@@ -39,6 +39,7 @@ export default class extends Controller {
     this.index = index; // index who communicates with nextPrev
     this.tabTargets.forEach((el, i) => {
       el.classList.toggle("current-tab", this.index == i) // displayig the speciefied tab of the form
+      $(el).closest('form[data-client-side-validations]').validate()
     })
     // Fixing Prev/Next buttons
     index === 0 ? this.prevBtnTarget.style.display = "none" : this.prevBtnTarget.style.display = "flex"

This should work

Read more comments on GitHub >

github_iconTop Results From Across the Web

isValid is sometimes false despite no errors · Issue #2755
I sometimes get isValid = false despite having no visible errors and ... the input/form, while isValid report the entire form valid state....
Read more >
How to clear jQuery validation error messages?
I consulted the source code for jquery.validate . Here is what I came up with: Clear errors by indicating validation success; Call handler...
Read more >
Form validation with React Hooks WITHOUT a library
In this article, I walk you through the process of creating a hook that you can use for managing forms without the use...
Read more >
Validate the fields of a form - OutSystems 11 Documentation
You assign False to the Valid property of any field of the form. The validation messages show next to all fields with invalid...
Read more >
Validate Input | Blazor
This form validates user input based on data annotation attributes defined in a model and indicates errors. The following table lists data ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found