Проверка коллекции MVC3 на стороне клиента, по крайней мере, один элемент со значением

Моя модель представления

Public Class ViewModel
  <SelectOne()>
  Public Property Collection As List(Of Item)
End Class

Моя модель

Public Class Item
  <SelectOneProperty(TargetValue:=True, ErrorMessage:="Select at least one.")>
  Public Property Selected As Boolean
  Public Property Value As String
End Class

На мой взгляд, я визуализирую ViewModel.Collection с помощью шаблона редактора.

@Html.CheckBoxFor(Function(item) item.Selected)
@Html.HiddenFor(Function(item) item.Value)

Теперь я хочу убедиться, что хотя бы один флажок отмечен с помощью проверки на стороне клиента.

Я могу добиться этого, установив собственный атрибут проверки для свойства Item.Selected и зарегистрировав новый адаптер через $.validator.unobtrusive.adapters.add().

Но я чувствую, что атрибут скорее должен быть в свойстве ViewModel.Collection, так как на стороне сервера я уже проверяю, имеет ли один из элементов коллекции Selected = True, используя эту пользовательскую проверку:

<AttributeUsage(AttributeTargets.Field Or AttributeTargets.Property, AllowMultiple:=False, Inherited:=False)>
Public Class SelectOneAttribute
    Inherits ValidationAttribute

    Protected Overrides Function IsValid(value As Object, validationContext As ValidationContext) As ValidationResult

        Dim list As IList

        If value Is Nothing Then
            Return Nothing
        End If

        If TypeOf value Is IEnumerable Then
            list = CType(value, IList)
        Else
            list = New Object() {value}
        End If

        Dim count As Integer = (From item In list
                                From prop In item.GetType().GetProperties()
                                Let attributes = prop.GetCustomAttributes(GetType(RequireOneOrMoreIndicatorAttribute), False)
                                Where attributes.Count > 0
                                From attribute In attributes
                                Where attribute.TargetValue = prop.GetValue(item, Nothing)).Count()
        If count > 0 Then
            Return Nothing
        End If

        Return New ValidationResult(FormatErrorMessage(validationContext.DisplayName))
    End Function
End Class

Он использует отражение SelectOnePropertyAttribute, чтобы найти, какое свойство проверять:

<AttributeUsage(AttributeTargets.Field Or AttributeTargets.Property, AllowMultiple:=False, Inherited:=False)>
Public Class SelectOnePropertyAttribute
    Inherits ValidationAttribute
    Implements IClientValidatable

    Public Property TargetValue As Object

    Public Sub New(targetValue As Object)
        Me.TargetValue = targetValue
    End Sub

    Public Overrides Function IsValid(value As Object) As Boolean
        Return True
    End Function

    Public Function GetClientValidationRules(metadata As System.Web.Mvc.ModelMetadata, context As System.Web.Mvc.ControllerContext) _
        As System.Collections.Generic.IEnumerable(Of System.Web.Mvc.ModelClientValidationRule) _
        Implements System.Web.Mvc.IClientValidatable.GetClientValidationRules

        Dim rule As New ModelClientValidationRule With {
            .ValidationType = "selectone",
            .ErrorMessage = Me.ErrorMessage
        }

        Return New ModelClientValidationRule() {rule}
    End Function
End Class

И это проверка на стороне клиента

$.validator.unobtrusive.adapters.add("selectone", function (options) {
    options.rules["selectone"] = {};
    options.messages["selectone"] = options.message;
});

$.validator.addMethod("selectone", function (value, element, parameters) {

    var $el = $(element),
        name = $el.attr("name"),
        field = name.replace(/\[.*$/, "").replace(".", "_"),
        attr = name.replace(/^.*\./, ""),
        test = new RegExp(field + "\\[\\d\\]\." + attr);

    var inputs = $("input[id^=" + field + "]:not([disabled]):not([type=hidden])").filter("input[name$=" + attr + "]");

    for(var i = 0; i < this.errorList.length; i++) {
        var name = $(this.errorList[i].element).attr("name");

        // Do not write out the error more than once.
        if (test.test(name)) return true;
    }

    return inputs.length == 0 || inputs.filter(":checked:not([disabled])").val();
});

person boulaycote    schedule 12.09.2012    source источник
comment
Я работаю над решением CustomValidation для вас. Я ненавижу VB, поэтому он будет на C#. Дайте мне знать, если это круто   -  person CrazyCoderz    schedule 15.09.2012
comment
Просто любопытно, разве вы не хотели бы иметь возможность точно определить, какой флажок вы хотите установить в своей ViewModel?   -  person CrazyCoderz    schedule 15.09.2012
comment
С# в порядке. Я хотел бы иметь возможность установить любую комбинацию свойства/значения. Не только логические значения.   -  person boulaycote    schedule 17.09.2012
comment
Я дал решение. Пожалуйста, проверьте его и дайте мне сейчас. Это полезно для вас.   -  person Pushpendra    schedule 18.09.2012
comment
Эй..Пожалуйста, проверьте ответ..Какой я вам дал?   -  person Pushpendra    schedule 19.09.2012
comment
Хотя бы ответь мне.. Ты проверял?   -  person Pushpendra    schedule 20.09.2012
comment
Я посмотрел на это. Извините, что не ответил раньше, не мог. Это не соответствует моим потребностям, как я это вижу сейчас. Он также довольно плохо отформатирован.   -  person boulaycote    schedule 21.09.2012


Ответы (3)


Вы создаете настраиваемую проверку, которая будет выполняться на стороне клиента, но если вы хотите работать на стороне клиента, вам нужно создать JQuery для этой пользовательской проверки, а затем на вашей странице.

Пожалуйста, обратитесь к ссылкам ниже

http://www.codeproject.com/Articles/275056/Custom-Client-Side-Validation-in-ASP-NET-MVC3

http://www.falconwebtech.com/post/2012/04/21/MVC3-Custom-Client-Side-Validation-with-Unobtrusive-Ajax.aspx

person Pushpendra    schedule 17.09.2012
comment
Может мой вопрос не ясен. Я уже могу добиться проверки на стороне клиента и на стороне сервера. Но я считаю, что мое решение (с использованием пользовательского атрибута проверки и регистрации адаптера для свойства Item.Selected) не является оптимальным. Я действительно хочу, чтобы атрибут проверки был установлен в свойстве списка, а не в свойстве элемента. - person boulaycote; 17.09.2012
comment
Я понимаю, потому что проверка, которую вы написали для ярлыка свойства, не могли бы вы прислать мне свою пользовательскую проверку, а также javascript, который вы написали, тогда я могу предоставить вам решение. - person Pushpendra; 17.09.2012
comment
Код, который у меня есть сейчас, работает нормально. Но мне действительно нужно другое решение. Тот, который будет применяться только к свойству List (если это возможно). - person boulaycote; 17.09.2012
comment
Пожалуйста, поделитесь этим кодом, тогда я смогу поработать над этим и дать вам правильный код - person Pushpendra; 17.09.2012

Внесите следующие изменения: -

1.Ваша ViewModel: -

Public Class ViewModel
  <SelectOne()>
  <SelectOneProperty(TargetValue:=True, ErrorMessage:="Select at least one.")>
  Public Property Collection As List(Of Item)
End Class
  1. Моя модель: -

    Публичное свойство элемента публичного класса, выбранное как логическое значение публичного свойства как String End Class

  2. В вашем представлении добавьте следующую строку:

    @Html.HiddenFor(x=>x.ItemCollection)

4. затем вы запустите представление и увидите источник представления, после чего он

4.And then you will submit the code then it will run client-side validation. add the debugger and Debug it

5. Затем измените сценарий на стороне клиента. 1. Теперь вы можете получить значение из каждого флажка и проверить, установлен ли какой-либо из ваших флажков, а затем отправить форму, иначе отобразите результат.

6. Также внесите изменения в SelectOnePropertyAttribute в соответствии с вашими требованиями.

7. А для серверной части я сделал этот код на С#: -

[AttributeUsage((AttributeTargets.Field | AttributeTargets.Property), AllowMultiple = false, Inherited = false)] открытый класс SelectOneAttribute: ValidationAttribute { public String PropertyName { get; набор; }

    protected override ValidationResult IsValid(object  value, ValidationContext validationContext)
    {
        bool boolVal = false;
        IList list;
        if (value == null)
        {
            return null;
        }
        if (value.GetType().Name == typeof(List<>).Name || value.GetType().Name == typeof(IList<>).Name)
        {
            list = (IList)value;
        }
        else
        {
            list = new object[] {value};
        }
        if (list.Count<0)
            return null;

        if ((from object item in list let propertyInfo = item.GetType().GetProperties() from info in propertyInfo where String.Equals(info.Name, PropertyName) && (bool)info.GetValue(item) == true select item).Any())
        {
            return null;
        }

        return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
    }
}
person Pushpendra    schedule 18.09.2012

Это то, что тебе надо? Это предотвратит отправку формы, если не установлен флажок "myCheckbox"...

$(document).ready(function () {
    $('#submitButtonId').click(function (e) {
        if ($('input[name=myCheckbox]:checked').length == 0) {
            e.preventDefault();
            alert('Please choose at least one checkbox before continuing!');
        }
    });
});
person leobelones    schedule 21.09.2012
comment
В некотором роде. Фактически, в коде, который я представил в своем вопросе, этот бит добавляется через $.validator.addMethod(). - person boulaycote; 21.09.2012