Question

-- 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.

Was it helpful?

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.

OTHER TIPS

The issue is here $("table tr").next("tr").each(...

You are selecting ALL next rows for each row in $("table tr"). To fix move the .next("tr") inside each().

Here is simplified fiddle

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top