Reputation: 7925
Models
public class Cidade
{
[Key]
public int Id { get; set; }
[Required]
public string Nome { get; set; }
}
public class Usuario
{
[Key]
public int Id { get; set; }
[Required]
public Cidade Cidade { get; set; }
/* more fields... */
}
Controller
public ActionResult Registrar()
{
using (var db = new MyContext())
{
ViewBag.Cidades = new SelectList(db.Cidades.ToList(), "Id", "Nome");
}
return View();
}
[HttpPost]
public ActionResult Registrar(Usuario usuario)
{
if (ModelState.IsValid)
{
using (var db = new MyContext())
{
db.Usuarios.Add(usuario);
db.SaveChanges();
}
return RedirectToAction("Index", "Home");
}
return Registrar();
}
View
@Html.LabelFor(m => m.Cidade)
@Html.DropDownListFor(m => m.Cidade, (SelectList)ViewBag.Cidades)
But ModelState.IsValid == false
always, because usuario.Cidade == null
.
:(
Upvotes: 0
Views: 55
Reputation: 17108
You bind to the model's property and not to the model itself. So instead of doing this
@Html.DropDownListFor(m => m.Cidade, (SelectList)ViewBag.Cidades)
you need to do this
@Html.DropDownListFor(m => m.Cidade.Id, (SelectList)ViewBag.Cidades)
But that would probably NOT solve your problem entirely because you have a required attribute for name. However, the way you use your model is also not the way you expect to use it in your view. So the question you should be asking yourself is: are you creating a Cidade
along with your Usuario
in your view? The answer to which I think is "no". The way I understand your setup based on your question is that you want to assign a Cidade
to a Usuario
that you are creating/editing.
This again is another case where you would use viewmodels, which is a standard practice, escpecially for this kind of thing. If you do not want to use viewomdel then you should at least change your Usuario into this:
public class Usuario
{
[Key]
public int Id { get; set; }
public Cidade Cidade { get; set; }
[Required]
public int CidadeId { get; set; }
}
Notice the additional CidadeId
and that it is marked as required. In your view you would then do this:
@Html.DropDownListFor(m => m.CidadeId, (SelectList)ViewBag.Cidades)
UPDATE:
The only inconvenient thing is have to see "Cidade" as null when debugging. Would be nice see it filled.
It really is not necessary and really not a good approach. But as always it can still be done if you really feel it fits your project. So you add a hidden field that will map to Cidade.Nome
@Html.HiddenFor(m => m.Cidade.Nome)
// then change your binding again to this
@Html.DropDownListFor(m => m.Cidade.Id, (SelectList)ViewBag.Cidades)
add a script to populate that field when the dropdown changes:
$("#Cidade_Id").change(function(){
$("#Cidade_Name").val($(this).text());
});
Upvotes: 1