Как правильно создавать условные формы в ASP.Net MVC3? - PullRequest
3 голосов
/ 15 августа 2011

Обзор проблемы:

Я хочу, чтобы в моей форме была условная логика. Пользователь делает выбор с помощью переключателя, и в зависимости от выбора я хочу скрыть некоторые поля и показать некоторые другие поля. Это также должно повлиять на проверку (скрытые поля не должны проверяться). Я думаю, что это типичная проблема, но я не смог найти никаких примеров, и мое собственное решение, кажется, имеет много слесарного дела.

Моя актуальная проблема:

Давайте начнем с классов viewmodel (несколько упрощенных для нужд этого вопроса):

public class Scenario
{
   public Request Request { get; set; }
   public Response Response { get; set; }
   // … some other properties
}

public class Request
{
   //some properties
}

public class Response
{
    [Required]
    public string ResponseType { get; set; }

    [Required]
    public string State { get; set; }

    [Required]
    [NotZero] //this is my custom validation attribute
    public string ErrorCode { get; set; }

    public string ErrorDescr { get; set; }
}

В моем представлении создания / редактирования для модели Scenario у меня довольно большая форма, состоящая из 3 вкладок. На 3-й вкладке я отображаю частичный вид на основе модели Response. Вот где я хочу условную логику. ResponseType свойство - переключатель в форме. Может иметь два значения: НОРМАЛЬНОЕ и ОШИБКА. В случае ОШИБКИ я хочу отобразить и проверить свойства ErrorCode и ErrorDescr. В случае NORMAL я хочу отобразить и проверить только свойство State.

Мое решение:

  1. В частичном представлении Response у меня есть некоторые вызовы jquery .hide () и .show (), подключенные для скрытия / отображения соответствующих элементов ввода.
  2. Я изменил ненавязчивый скрипт проверки jquery, чтобы он не проверял скрытые поля (http://blog.waynebrantley.com/2011/01/mvc3-validates-hidden-fields-using.html)
  3. В контроллере Scenario у меня есть такой код:

    public ActionResult Edit(int id, Scenario scenario)
    {
       Response response=scenario.Response;
       if (response.ResponseType != null)
       {
          if (response.ResponseType == "NORMAL")
          {
             //in this case remove validation for errorcode
             this.ModelState.Remove("Response.ErrorCode");
          }
          else
          {
             //in this case remove validation for state
             this.ModelState.Remove("Response.State");
          }
       }
       if (ModelState.IsValid)
       {
           //map to entity and save to database
       }
    }
    

Это много уродливого слесарного дела (особенно кода контроллера - удаление элементов из ModelState с помощью строкового ключа ... без безопасности типов и т. Д.), наверняка должен быть лучший способ?

Ответы [ 2 ]

1 голос
/ 16 августа 2011

Вы можете попробовать наследовать от IValidateableObject в вашем классе Response и выполнить условную проверку в Validate. Вот так:

public class Response : IValidateableObject
{
    [Required]
    public string ResponseType { get; set; }
    public string State { get; set; }   
    public string ErrorCode { get; set; }
    public string ErrorDescr { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (ResponseType == "NORMAL")
        {
            if (State.IsNullOrWhiteSpace)
                yield return new ValidationResult("State is required", new [] { "State" });
        }

        // additional validations...
    }
}
0 голосов
/ 03 января 2019

Это довольно старое время, и мне не нравится, когда оно без ответа, поэтому я отвечу сам.

Правильным решением является реализация пользовательского атрибута проверки, а также реализация интерфейса IClientValidatable. Это удовлетворяет всем требованиям - отсутствие подключения внутри контроллера и последовательная проверка на стороне клиента.

В настоящее время я, вероятно, даже не реализовал бы это сам - я бы использовал существующую библиотеку, такую ​​как ExpressiveAnnotations , которая предоставляет приятный и гибкий атрибут RequiredIf:

public class Response
{
    [Required]
    public string ResponseType { get; set; }

    [RequiredIf("ResponseType == 'NORMAL'"]
    public string State { get; set; }

    [RequiredIf("ResponseType == 'ERROR'"]
    public string ErrorCode { get; set; }

    public string ErrorDescr { get; set; }
}

Атрибут работает как на стороне сервера, так и на стороне клиента, если вы настроите его, добавив несколько строк в Global.asax и включив JavaScript с валидаторами. Вы можете прочитать подробности на странице проекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...