2010-11-14 3 views
7

Ho una classe viewmodel che contiene un paio di proprietà. In pratica, il record corrente (che l'utente sta modificando) e un elenco di opzioni (che viene utilizzato per compilare un elenco a discesa utilizzando DropDownListFor).MVC DropDownListFor - Devo reinserire manualmente le opzioni dopo il fallimento della convalida?

Dopo aver inviato il modulo, se lo stato del modello non è valido, ritorno alla visualizzazione. Comprendo che il modulo viene compilato utilizzando l'input "rifiutato" da ModelState["name"].Value.AttemptedValue, ma non sono sicuro di cosa fare sull'elenco di valori per l'elenco a discesa.

Se non faccio nulla, in caso di errore di convalida e ritorno alla pagina, viene visualizzato un errore 'riferimento oggetto non impostato su istanza di un oggetto' perché la proprietà elenco di viewmodel è nullo. So che è nullo perché non è stato rilegato dal post del modulo, quindi posso ripopolarlo dal database prima di tornare alla visualizzazione.

È il modo corretto per farlo, o mi manca un modo più ovvio per mantenere i valori di dropdown persistenti?

risposta

10

Sì, questo è il modo corretto se si ha intenzione di restituire la stessa vista nell'azione POST:

  1. legano la lista nell'azione GET dal database
  2. rendere la vista
  3. l'utente invia il modulo all'azione POST
  4. in questa azione si recupera solo il valore selezionato, quindi se il modello non è valido ed è necessario rivisualizzare la vista è necessario recuperare l'elenco dal database per popolare il modello di visualizzazione.

Ecco un esempio di un modello comunemente usato in MVC:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     var model = new MyViewModel 
     { 
      Items = _repository.GetItems() 
     }; 
     return View(model); 
    } 

    [HttpPost] 
    public ActionResult Index(MyViewModel model) 
    { 
     if (!ModelState.IsValid) 
     { 
      // Validation failed, fetch the list from the database 
      // and redisplay the form 
      model.Items = _repository.GetItems(); 
      return View(model); 
     } 
     // at this stage the model is valid => 
     // use the selected value from the dropdown 
     _repository.DoSomething(model.SelectedValue); 
     // You no longer need to fetch the list because 
     // we are redirecting here 
     return RedirectToAction("Success", "SomeOtherController"); 
    } 
} 
+0

Grazie. È praticamente la tecnica che stavo usando. Solo lavorando da solo su un progetto che utilizza una nuova tecnologia, è bene controllare un secondo parere! – Gavin

0

È possibile utilizzare chiamate XHR ajax per inviare i dati, invece di presentare il modulo è di default pulsante di invio.

Il vantaggio di questa tecnica è che non è necessario ripopolare le liste.

Sul lato client e dopo chiamata AJAX indietro si può decidere di fare quello che vuoi con un assegno del valore status

$.ajax({ 
    url: '@Url.Action("Index", "Controller")', 
    data: $("#form").serialize(), 
    type: 'POST', 
    success: function (data) { 
     if (data.status == "Successful") { 
      // you can redirect to another page by window.location.replace('New URL') 
     } else { 
      // you can display validation message 
     } 
    } 
}); 

È ActionMethod sarà come:

[HttpPost] 
     public JsonResult Index() 
     { 
      if (ModelState.IsValid) 
      { 
       return Json(new { status = "Success" });  
      } 
      else 
      { 
       return Json(new { status = "Fail" }); 
      } 
     } 
Problemi correlati