2011-01-25 11 views
7

Ho un semplice elenco a discesa, il primo elemento nell'elenco ha un valore vuoto. Se non seleziono nulla nell'elenco, la convalida del client lo ignora. Ho impostato quel campo come richiesto sul modello usando gli attributi di annotazione.ASP.Net MVC 3 convalida client non invadente non funziona con elenchi a discesa

@Html.DropDownListFor(model => Model.CCPayment.State, UnitedStatesStates.StateSelectList) 



[Required(ErrorMessage = "State is Required.")] 
    public string State 
    { 
     get 
     { 
      return _state; 
     } 
     set 
     { 
      _state = value; 
     } 
    } 

qualche idea? mi sto perdendo qualcosa?

+0

Aggiungere le caselle di controllo anche a questo, ho una casella di controllo richiesta che non è illuminata come un campo di errore quando non è selezionata. – JBeckton

+0

Non è davvero una risposta, più una soluzione alternativa, ma hai provato a utilizzare l'interfaccia IValidatableObject - potrebbe aiutarti per ora? – RichardW1001

+3

Sto già utilizzando IValidatableObject per la validazione lato server. Questo è un problema lato client. Ho trovato un problema aperto in codeplex per questo http://aspnet.codeplex.com/workitem/7629 – JBeckton

risposta

4

Hai fornito troppe informazioni per consentirci di individuare il problema. Potresti aver dimenticato di includere gli script di convalida non intrusivi nella tua vista, ma chi lo sa? Non hai mostrato la tua vista.

Ecco un esempio di lavoro completo:

Modello:

public class MyViewModel 
{ 
    [Required(ErrorMessage = "State is Required.")] 
    public string State { get; set; } 

    public IEnumerable<SelectListItem> States 
    { 
     get 
     { 
      return Enumerable.Range(1, 5).Select(x => new SelectListItem 
      { 
       Value = x.ToString(), 
       Text = "state " + x 
      }); 
     } 
    } 
} 

Controller:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     return View(new MyViewModel()); 
    } 

    [HttpPost] 
    public ActionResult Index(MyViewModel model) 
    { 
     return View(model); 
    } 
} 

Vista:

@model AppName.Models.MyViewModel 
@{ 
    ViewBag.Title = "Home Page"; 
} 
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script> 

@using (Html.BeginForm()) 
{ 
    @Html.LabelFor(x => x.State) 
    @Html.DropDownListFor(
     x => x.State, 
     new SelectList(Model.States, "Value", "Text"), 
     "-- Please select a state --" 
    ) 
    @Html.ValidationMessageFor(x => x.State) 
    <input type="submit" value="OK" /> 
} 

Notate come ci stanno fornendo un valore di default in il Assistente DropDownListFor come ultimo parametro. Ciò inserirà un'opzione all'inizio con valore vuoto e testo personalizzato e se l'utente non sceglie lo stato il validatore richiesto dovrebbe dare il via.

+0

dovrebbe entrare ma non funziona, ho provato ad aggiungere il valore predefinito ma ho lo stesso problema. L'unico modo per farlo funzionare è aggiungere "required" all'attributo della classe html. il problema è che fornisce solo un messaggio di errore generico piuttosto che quello che ho specificato nell'attributo di convalida del mio modello. – JBeckton

+0

È stato eliminato anche per me. Se escludo jq.validate.js e includo solo jq.validate.unobtrusive.js, funziona, il che è strano. –

2

Ho aggiunto @ class = "required" agli attributi come ha detto qualcuno sul filo a CodePlex http://aspnet.codeplex.com/workitem/7629 e ha funzionato bene per me =)

+0

sì, questo è un problema, ma si ottiene il messaggio di errore generico piuttosto che quello personalizzato definito nell'attributo di convalida. – JBeckton

8

sembra un bug legittima, ecco la soluzione migliore che ho trovato nella mia ricerca:

http://forums.asp.net/t/1649193.aspx

in breve. Si avvolgono l'origine del problema, DropDownListFor, in un'estensione Html personalizzato e di recuperare manualmente i discreti regole di validazione lato client come questo:

IDictionary<string, object> validationAttributes = htmlHelper. 
    GetUnobtrusiveValidationAttributes(
     ExpressionHelper.GetExpressionText(expression), 
     metadata 
    ); 

Poi si combinano il dizionario validationAttributes con altri attributi HTML passati in vostro aiuto personalizzato e si passa che insieme a DropDownListFor

Il codice completo che sto usando (ho un'etichetta anche lì, si può sentire libero di disaccoppiare):

public static IHtmlString DropDownListWithLabelFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, string label, IEnumerable<SelectListItem> items, string blankOption, object htmlAttributes = null) 
{ 
    var l = new TagBuilder("label"); 
    var br = new TagBuilder("br"); 

    var metadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData); 
    var mergedAttributes = helper.GetUnobtrusiveValidationAttributes(ExpressionHelper.GetExpressionText(expression), metadata); 

    if (htmlAttributes != null) 
    { 
     foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(htmlAttributes)) 
     { 
      object value = descriptor.GetValue(htmlAttributes); 
      mergedAttributes.Add(descriptor.Name, value); 
     } 
    } 

    l.InnerHtml = label + br.ToString(TagRenderMode.SelfClosing) + helper.DropDownListFor(expression, items, blankOption, mergedAttributes); 
    return MvcHtmlString.Create(l.ToString(TagRenderMode.Normal)); 
} 
+0

Oltre me come questa non è la risposta accettata? +1 –

+0

Seriamente questa è sicuramente la risposta !!! Stavo lavorando su questo per tre giorni! Non l'avrei mai capito. Eccezionale!!! Grazie @Milimetric – Rich

+0

Questo mi ha salvato dopo ore di arrivare da nessuna parte !!! Dovrebbe essere contrassegnato come la risposta! – Nick

1

Questo è il modo più semplice che ho trovato per farlo, aggiungendo semplicemente gli attributi data-val-*-* in HtmlAttributes di DropDownListFor, all'interno della vista. Il seguente metodo funziona con RemoteValidation troppo, se non hai bisogno di validazione a distanza, è sufficiente rimuovere gli elementi che contengono data-val-remote-*:

 @Html.DropDownListFor(m => m.yourlistID, (IEnumerable<SelectListItem>)ViewBag.YourListID, String.Empty, 
     new Dictionary<string, object>() { { "data-val", "true" }, 
     { "data-val-remote-url", "/Validation/yourremoteval" }, 
     { "data-val-remote-type", "POST" }, { "data-val-remote-additionalfield", "youradditionalfieldtovalidate" } }) 

Spero che possa aiutare. I migliori saluti!