Search code examples
asp.net-mvcvalidationunobtrusive-validationrequiredfieldvalidator

Remove/Add asterisk for requiredif when dependent property changes value


I have the following scenario: Multiple requiredif DataAnnotation attributes. I made a custom label helper that renders a "*" aside for the properties that are decorated if requiredif attribute. Now on the clientside I want to be able to hide/show if the dependent property changes value.

For a more precise example I have a model

public class Document {
public bool IsFake {get; set; }

[RequiredIf("IsFake",false,ValueComparison.IsEqual)]
public string Number{ get; set; }
}

Based on the label helper that I made I have the corresponding label for Number with a red * in the UI. When I change on the client side from the is fake to the is not fake radio button I want to hide the *.

I want to do be able to make this changes automatic and not make a script that for the known fields does that, as I have multiple cases like this.

I was thinking maybe I could write a javascript code that attaches dynamically a change event to the dependent property input and a handler that would show/hide the required mark.


Solution

  • This is pretty much the solution which I came up with. It is the best I could do, but still needs some customization meaning that the span that contains the "*" it's custom for my pages' DOM.

                <div class="editor-label">
                    <label ui-documentLabel" for="Number">Number<span class="span-required">*</span></label>
                </div>
                <div class="editor-field">
                    <input class="k-textbox ui-textbox" data-val="true" data-val-requiredif="The field Number is required!" data-val-requiredif-dependentproperty="IsFake" data-val-requiredif-dependentvalue="False" data-val-requiredif-operator="IsEqual" id="Number" name="Number" value="" type="text">
                    <span class="field-validation-valid" data-valmsg-for="Number" data-valmsg-replace="true"></span>
                </div>
    

    and the javascript

      var clietsidevalidation = function () { };
    
     clietsidevalidation.is = function (value1, operator, value2) {
    //function that verifies that the comparison between value1 and value2 is true or not
    };
    
     clietsidevalidation.handleRequirefIf = function (container) {
    
    
    
    $('input', container).filter(function () {
        var attr = $(this).attr('data-val-requiredif');
        return (typeof attr !== 'undefined' && attr !== false);
    }).each(function (index, item) {
    
        var params = new Array();
        params["operator"] = $(this).attr('data-val-requiredif-operator');
        params["dependentvalue"] = $(this).attr('data-val-requiredif-dependentvalue');
        params["dependentproperty"] = $(this).attr('data-val-requiredif-dependentproperty');
    
        var dependentProperty = clietsidevalidation.getName(this, params["dependentproperty"]);
        var dependentTestValue = params["dependentvalue"];
        var operator = params["operator"];
        var dependentPropertyElement = document.getElementsByName(dependentProperty);
        params["element"] = this;
    
    
        $(dependentPropertyElement).on('change', { params: params }, function (e) {
            var input = e.data.params.element;
            var inputName = $(input).attr("name");
            var $span = $('label[for=' + inputName + '] span', '.editor-label');
    
            var dependentProperty = this;
            var dependentTestValue = e.data.params["dependentvalue"];
            var operator = e.data.params["operator"];
            var dependentPropertyElement = $(this);
    
            var dependentValue = null;
    
            if (dependentPropertyElement.length > 1) {
                for (var index = 0; index != dependentPropertyElement.length; index++)
                    if (dependentPropertyElement[index]["checked"]) {
                        dependentValue = dependentPropertyElement[index].value;
                        break;
                    }
    
                if (dependentValue == null)
                    dependentValue = false
            }
            else
                dependentValue = dependentPropertyElement[0].value;
    
            if (clietsidevalidation.is(dependentValue, operator, dependentTestValue) == false) {
    
                $span.addClass('hidden');
    
                var $form = $span.closest("form");
                // get validator object
                var $validator = $form.validate();
    
                var $errors = $form.find("span.field-validation-error[data-valmsg-for='" + inputName + "']");
                // trick unobtrusive to think the elements were succesfully validated
                // this removes the validation messages
                //custom form our solution as the validation messages are differently configured DOM
                $errors.each(function () { $validator.settings.success($('label',this)); })
    
                // clear errors from validation
                $validator.resetForm();
            }
            else {
                $span.removeClass('hidden')
            }
        });
    
    });
     };
    

    This is inspired by another post which I can't find right now, but when I do I will post a link.