7

Scenario: I have a form with several accordions (that are expandable divs), each one has some required fields, the user is free to collapse or expand them, so, in some cases, there are non filled mandatory hidden fields (because collapse) when form is submitted.

Problem: In Chrome, no errors appears to user, only in the console you can read:

An invalid form control with name='' is not focusable.

I've found plenty of answers to this issue. I exactly know why is this happening, but I've not found any solution to my problem.

What i've tried: Before submitting the form, expand all accordions to make visible all required fields so I can allow browser to focus element and show Required field message (see update)

Desired solution: identify id of mandatory field that requires a content, to expand it's accordion container and focus the field

UPDATE: Solution found expanding all collapsable divs by javascript is not working in all cases, so IS NOT a solution.

QUESTION: there is some way can I show the field before validation?? If no... Can I focus or identify a hidden mandatory field when submitting form.

Jordi Castilla
  • 26,609
  • 8
  • 70
  • 109

2 Answers2

8

I personally would go with Niet the Dark Absol's suggestion about checking fields when changing section and displaying warning flags (I think it would give a better user experience).

But if you want to continue with the check on form submission, there's a way of tricking the browser into doing what you want by using JavaScript. The browser identifies and highlights the first invalid field that is visible when the page validates (for IE and FF it will highlight all the invalid fields that are visible); so, before the form validation happens, you'd need to run a quick check and open the accordion section that contains the first invalid field.

The key is to run that check before the HTML5 validation happens. That means that onsubmit is not good enough, as the browser will validate before the submit event. You need to run the code when the submit button/image is clicked, as that click event happens before the browser validates the fields.

You didn't specify if it was for jQuery UI or Bootstrap, so here are examples for both (the code is similar, just changing the way to handle opening/closing the accordion):

JQUERY UI ACCORDION

You can see a working demo for jQuery UI on this JSFiddle: http://jsfiddle.net/ma8v32ug/1/. The JavaScript check would be like this:

// save the accordion in a variable as you'll need it later
$accordion = $("#accordion").accordion();

// when the submit is clicked
$("#myForm input[type='submit']").on("click", function(event) {

    // traverse all the required elements looking for an empty one
    $("#myForm input[required='required']").each(function() {

        // if the value is empty, that means that is invalid
        if ($(this).val() == "") {

            // find the index of the closest h3 (divide by 2 because jQuery UI accordion goes in pairs h3-div. A bit hacky, sorry)
            var item = $(this).closest(".ui-accordion-content").prev().index() / 2;

            // open that accordion section that contains the required field
            $accordion.accordion("option","active", item);

            // stop scrolling through the required elements
            return false;
        }
    });
});

BOOTSTRAP ACCORDION

Note: this is valid for version 3.3.4 of Bootstrap. I haven't checked in older or newer versions.

One important thing to take into account for Bootstrap is that you cannot use the .collapse({toggle: true}) functionality because the animation takes more time than what the browser needs to validate the form, and the result will be unexpected (normally, the browser will stop the animation to point at the error, and it will not be the field that you want).

A solution to that is to do the toggle without animation, just by changing the .in class in the panels, and adjusting the target panel height. In the end, the function would look really close to the one for jQuery UI, just changing slightly:

// when the submit is clicked
$("#myForm input[type='submit']").on("click", function(event) {

    // traverse all the required elements looking for an empty one
    $("#myForm input[required='required']").each(function() {

        // if the value is empty, that means that is invalid
        if ($(this).val() == "") {

            // hide the currently open accordion and open the one with the invalid field
            $(".panel-collapse.in").removeClass("in");
            $(this).closest(".panel-collapse").addClass("in").css("height","auto");

            // stop scrolling through the required elements
            return false;
        }
    });
});

You can see it working on this JSFiddle: http://jsfiddle.net/ma8v32ug/2/

Community
  • 1
  • 1
Alvaro Montoro
  • 28,081
  • 7
  • 57
  • 86
  • Almost done, problem is I use `bootstrap`, not `jqueryUI`, I almost achieved my goal, I can identify mandatory field empty, now problem is: same function working to expand accordions at the begining the divs: `$("#" + itemId).collapse({toggle: true});` is not working in the moment I found empty mandatory field... any idea??? – Jordi Castilla Apr 02 '15 at 16:12
  • 1
    You should have specified Bootstrap in the question. Anyway, the code is quite similar. The only thing is that you cannot open/collapse the panels with the animation because the form validation will happen before the animation completes and it will break the effect. So just do it manually using jQuery. I updated the answer with a Bootstrap solution. – Alvaro Montoro Apr 02 '15 at 16:58
  • Alvaro, sorry for delay, Easter... >;) anyway, it works like charm! Thanks so much for you effort, explanation and modifications... – Jordi Castilla Apr 07 '15 at 07:26
  • This solution works for inputs that are of type text, is there a solution for radio buttons that are required inputs? – nils Aug 07 '16 at 20:57
  • @nils use `:input` to detect all input types in rather than just specific type of `` – MrLewk Mar 29 '18 at 12:26
  • I know this is an old question, but it comes up high in Google searches. I had an issue with detecting a multi select which had been converted into a tagging interface. To check if something like that is empty you will need to add: `if ($(this).val() === "" || $.isEmptyObject($(this).val())) {` – MrLewk Mar 29 '18 at 12:28
  • 1
    @MrLewk Any improvement/recommendation is welcomed, no matter how old the question is. Let me check and update the answer. – Alvaro Montoro Mar 29 '18 at 12:50
4

This is probably all kinds of bad user-experience, but I don't know much about that so I won't go into it XD Basically, as you can tell just from the practicality issues you're facing as the programmer, hiding required fields is bad.

I would suggest implementing validation yourself, such as in change events. Check for the validity of all input elements within that accordion section, and if any of them fail you can put a warning flag on the accordion's header bar and disable the submit button.

Only when all fields pass validation do you then enable the submit button and allow the user to continue.

Of course, this does defeat the purpose of the native validation that HTML5 provides, but you're already using non-native accordions so you kind of have to go non-native for your validation to work.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592