Search code examples
jquerydynamicform

Step through form as all inputs are completed in a row


-- FIDDLE --

I'm designing a form that acts like a wizard, walking the user through each input, and not allowing them to continue until all inputs have been addressed.

I want to show the next row in the table if and only if all inputs in the current row have either been filled out or checked. Rows may contain any number of text inputs, checkboxes, or radio groups.

Here's my current code:

<table>
    <tr>
        <td><input type="text"></td>

        <td><input type="radio"></td>
    </tr>

    <tr style="display:none">
        <td><input type='radio'></td>

        <td><input type='checkbox'></td>
    </tr>

    <tr style="display:none">
        <td><input type='text'></td>

        <td><input type='text'></td>
    </tr>
</table>​

function refreshCascadingLists() {
    // Get an array of tr's
    // Loop thorugh each and see if it should be shown based on it's predecessors status
    var prevHadUnselected = false;
    $("table tr").next("tr").each(function(curIdx, curEntity) {
        if (prevHadUnselected) {
            $(this).fadeOut();
        } else {
            $(this).fadeIn();
        }

        prevHadUnselected = false;
        $(this).find(":input").each(function(curSelIdx, curSelEntity) {
            if ($(curSelEntity).val() == "" && $(curSelEntity).not(":checked")) 
                prevHadUnselected = true;
        });
    });
}

$(document).ready(function() {
    $(":input").bind('keyup change', function() {
        refreshCascadingLists();
    });
});​

This will show the next row when the user types into the text box in the first row, but they should also have to check the radio button. Furthermore, it's displaying ALL of the rows in the table, instead of just the next one.


Solution

  • I would do something like this:

    function refreshCascadingLists($tr) {
        var all_filled = true;
        $tr.find(':input').each(function() {
            if($(this).is('input[type=radio], input[type=checkbox]')) {
                if(!$(this).is(':checked')) {
                    all_filled = false;    
                }
            } else if($(this).val() == '') {
                all_filled = false;
            }
        });
    
        var $next_tr = $tr.next('tr');    
        if(all_filled) {
            if(!$next_tr.is(':visible')) {
                $next_tr.fadeIn(function() {
                    refreshCascadingLists($(this));                    
                });    
            }
        } else {
            $tr.nextAll('tr').hide();
        }
    }
    
    $(document).ready(function() {
        $(":input").bind('keyup change', function() {
            refreshCascadingLists($(this).closest('tr'));
        });
    });​
    

    Most of the function could actually be golfed down quite a bit, but I wrote it like that so you can easily see what it is doing.