16

I have the following model:

public class Customer
{
    public string FirstName {get;set;}

    public string LastName {get; set;}

    [Remote("CardExisting", "Validation", AdditionalFields="FirstName,LastName")
    public string CardNumber {get; set;}
}

CardExisting action will check that there is an existing record for the combination of cardNumber for the firstName and LastName.

What if user will first enter the card number and then his name, I cant validate him, so when he returns and input his name I need to remote validate again, how can I do that when focus was already lost from cardnumber property?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Guy Z
  • 683
  • 3
  • 8
  • 24

4 Answers4

24

Expanding on Jaluka's answer, I wrote this helper method that finds each remotely validating element that has "additional fields," and then causes validation on said element to fire each time one of those fields changes.

// I hate naming things
function initializeRemotelyValidatingElementsWithAdditionalFields($form) {
    var remotelyValidatingElements = $form.find("[data-val-remote]");

    $.each(remotelyValidatingElements, function (i, element) {
        var $element = $(element);

        var additionalFields = $element.attr("data-val-remote-additionalfields");

        if (additionalFields.length == 0) return;

        var rawFieldNames = additionalFields.split(",");

        var fieldNames = $.map(rawFieldNames, function (fieldName) { return fieldName.replace("*.", ""); });

        $.each(fieldNames, function (i, fieldName) {
            $form.find("#" + fieldName).change(function () {
                // force re-validation to occur
                $element.removeData("previousValue");
                $element.valid();
            });
        });
    });
}

Call the function like so:

$(document).ready(function() {
    initializeRemotelyValidatingElementsWithAdditionalFields($("#myFormId"));
});
Chris Staley
  • 2,370
  • 1
  • 20
  • 21
  • 1
    W00t!!! Two days ago you answered this and I needed it just now... your code works GREAT! :) In my case I have 2 dropdowns that must work together, that is, one is the additional field of the other. Beautiful solution for something that should be default IMHO. :) – Leniel Maccaferri Jul 22 '13 at 05:39
  • hehehe I also don't like naming things... but given the nature of our profession it's inherently necessary multiple times a day! :D – Leniel Maccaferri Jul 22 '13 at 08:04
  • 1
    Indeed, can't believe this is not the default behaviour. Lame. Thanks @Kiff and Jaluka – MemeDeveloper Nov 22 '13 at 11:47
6

The way I have got this working is by adding some JavaScript.

$("#FirstName").change(function () {
  $('#CardNumber').removeData('previousValue');
  $('#CardNumber').valid();
});

So when the first name is changed you clear any previous values from the card number and re-validate the card number.

MarredCheese
  • 17,541
  • 8
  • 92
  • 91
Jaluka
  • 61
  • 2
4

if you don't like to create client scripts:

    public class Customer
    {
        [Remote("CardExisting", "Validation", AdditionalFields = "CardNumber,LastName")]
        public string FirstName { get; set; }
        [Remote("CardExisting", "Validation", AdditionalFields = "FirstName,CardNumber")]
        public string LastName { get; set; }
        [Remote("CardExisting", "Validation", AdditionalFields = "FirstName,LastName")]
        public string CardNumber { get; set; }
    }

And validate in CardExisting all fields are filled or not

Oleg Sh
  • 8,496
  • 17
  • 89
  • 159
0

Following on from Chris's helper method above. This works great in most instances, but if your model has a prefix at all e.g. 'Custom.Address.Line1' . The additional fields are not found correctly. I have updated the helper with some additional logic from the jquery.validate.unobstructive lib which will lookup the fields correctly.

function getModelPrefix(fieldName) {
    return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
}

function appendModelPrefix(value, prefix) {
    if (value.indexOf("*.") === 0) {
        value = value.replace("*.", prefix);
    }
    return value;
}

function escapeAttributeValue(value) {
    // As mentioned on http://api.jquery.com/category/selectors/
    return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
}

function initializeRemotelyValidatingElementsWithAdditionalFields($form) {
    const remotelyValidatingElements = $form.find("[data-val-remote]");

    $.each(remotelyValidatingElements, function (i, element) {
        var $element = $(element);

        const additionalFields = $element.attr("data-val-remote-additionalfields");

        if (additionalFields.length === 0) return;

        const rawFieldNames = additionalFields.split(",");
        const prefix = getModelPrefix(element.name);

        const fieldNames = $.map(rawFieldNames, function(fieldName) {
            return appendModelPrefix(fieldName, prefix);
        });

        $.each(fieldNames, function (i, fieldName) {
            $form.find(":input").filter("[name='" + escapeAttributeValue(fieldName) + "']").change(function () {
                // force re-validation to occur
                $element.removeData("previousValue");
                $element.valid();
            });
        });
    });
}
johnw86
  • 121
  • 1
  • 6