jwaliszko / ExpressiveAnnotations

Annotation-based conditional validation library.
MIT License
351 stars 123 forks source link

Hide non-required elements #121

Closed rickparrish closed 7 years ago

rickparrish commented 8 years ago

If a RequiredIf condition evaluates to false, is it possible to hide that element on the form (and then of course show it again when the condition is satisfied)? Ideally this would be by a callback passing the name of the element to show/hide, since it would actually be a wrapper div with a similar name that I would want to show/hide.

If yes, can this be chained? i.e. question 2 depends on question 1, and question 3 depends on question 2. So if question 2 gets hidden, question 3 needs to be hidden as well.

Thanks, Rick

jwaliszko commented 8 years ago

With the changeset https://github.com/jwaliszko/ExpressiveAnnotations/commit/b18fe070023a10ba0a1a69965820a7a89623940d, elements validated by EA trigger an eavalid event with the following arguments:

Based on that you are able to do what you've requested, e.g. (some customization may be required)

$('form').find('input, select, textarea').on('eavalid', function(e, type, valid, expr) {
    if (type === 'requiredif') {
        var div = $(e.currentTarget).parent().closest('div');
        div.css('visibility', !valid ? 'visible' : 'hidden'); // or, div.toggle(!valid) - see comments below
    }
});

For div sections collapse, instead of div.css('visibility', !valid ? 'visible' : 'hidden'), use div.toggle(!valid). Note that for this to work, validation for :hidden fields has to be enabled, i.e.

$(document).ready(function() {
    var validator = $('form').data('validator'); // get validator associated with the form (association established by jquery.validate.unobtrusive.js)
    validator.settings.ignore = '';

For details see: https://jqueryvalidation.org/validate/#ignore, https://api.jquery.com/hidden-selector/.

jwaliszko commented 8 years ago

UPDATE More complete function would be as follows:

function hideNonRequiredFields() {
    var $form = $('form');
    var current = undefined;
    var selector = 'input, select, textarea';

    $form.validate().settings.ignore = '';
    $form.find(selector).on(ea.settings.dependencyTriggers, function() {
        current = this; // mark element being currently modified
    });
    $form.find(selector).on('eavalid', function(e, type, valid, expr) {
        if (type === 'requiredif' && e.currentTarget !== current) {
            $(e.currentTarget).parent().closest('div').toggle(!valid);
        }
    });
}
rickparrish commented 8 years ago

Thanks for the quick response!

Basing the visibility on the result of computeRequiredIf() wasn't exactly what I needed since the call to modelHelper.ctxEval() is bypassed for elements that have a value, and I want to hide such elements if the RequiredIf expression fails, so I need modelHelper.ctxEval() to be called regardless of whether the element has a value.

Your change pointed me in the right direction though, so after fiddling around with a few things I think I have it working the way I'd like now...although I only used a small 3 question test form, so I'll find out if it's really working when I try to build something more complex next week.

https://github.com/rickparrish/ExpressiveAnnotations/commit/893c724bf929111c945b1d70c88e3c2f804a891a is the changes I made, if you'd like to have a look. Hopefully I didn't screw anything up too horribly!

jwaliszko commented 8 years ago

Hi. If you want to be compatible with legacy logic what I can recommend is to run test.ps1 script. If output is green, all the covered usage cases are passing, so you are most likely safe.

Forgive me please not digging into the details of your requirements but I'm running out of time to give best solution. The changes at first sight look OK. It would be safest to use existing code to solve what you need, but if it is not possible (which is perfectly fine), fork is the way to go.

jwaliszko commented 7 years ago

Hi, issue is reopened due to very similar use case reported in the referenced issue.