I'm stuck creating a proper create/edit view in ASP.NET MVC5. I've got two models Dog
and Human
. A dog belongs to one Human
. I'm trying to create a dropdown in the create
and edit
views for Dog
that'll allow me to select a Human
by name for that particular Dog
. Here are my models:
Human:
public class Human
{
public int ID { get; set; }
public string Name { get; set; }
}
Dog:
public class Dog
{
public int ID { get; set; }
public string Name { get; set; }
public Human Human { get; set; }
}
My create action:
// GET: /Dog/Create
public ActionResult Create()
{
ViewBag.HumanSelection = db.Humen.Select(h => new SelectListItem
{
Value = h.ID.ToString(),
Text = h.Name
});
return View();
}
And here is the relevant part of my view:
<div class="form-group">
@Html.LabelFor(model => model.Human.Name, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model => model.Human, ViewBag.HumanSelection);
</div>
</div>
I get the following error when I run this:
Compiler Error Message: CS1973: 'System.Web.Mvc.HtmlHelper<Test.Models.Dog>' has no applicable method named 'DropDownListFor' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.
I'm new to C# & the Entity framework. What am I doing wrong? Is there a way of doing this without manually querying the database? Something like the collection form helpers in Rails? I've followed a bunch of tutorials that are either old or too complicated for me to follow.
Important to note is that if you use DropDownListFor(x => x.Human)
, the returned value of the dropdownlist should be a Human
object.
It isn't. In your own code snippet, you set the value of the SelectListItem
to the ID of the Human. Therefore, when you submit your form, you will receive the ID that you selected.
Add the following to your model:
public int HumanId { get; set; }
Bind your dropdownlist to that int:
@Html.DropDownListFor(model => model.HumanId, (SelectList)ViewBag.HumanSelection);
Now, when you get back to the controller, use that ID to look up the actual Human you want:
[HttpPost]
public ActionResult Create (CreateModel model)
{
if(model.HumanId > 0)
{
model.Human = GetHumanByID(model.HumanId);
//or however you want to get the Human entoty from your database
}
}
It's a simplified solution, but I suspect your main confusion stems from the fact that you're expecting to receive a Human from the DropDownList, while it will actually only return an int (the ID).
Edit
I don't have much information on your data model, but if you're using entity framework, odds are that your Dog
class will have a foreign key property called HumanId
. If that is the case, you don't even need to get the Human
entity like I showed you before. If you put the selected ID in the HumanId
property, Entity Framework should be able to use that to create the relation between Human/Dog you want.
If this is the case, it would seems best to elaborate on this in your question, as this would otherwise be more guesswork than actual confirmation.
Edit 2 going offtopic here
Your code:
db.Humen
The plural form of man
is men
, woman
is women
; but for human
, it's humans
:) Humen does sounds like an awesome suggestion though ;)
The problem is that you are attempting to bind a Human
type to a dropdown in the UI, a dropdown whose values are strings (the IDs of Human
instances) and text are also strings (the names of Human
instances).
What you should be binding to the dropdown instead is the ID of the Human
, to match the fact that the ID is being used as the value. So with a view model such as
public class CreateDogModel
{
public string Name { get; set; }
[Range(0, int.MaxValue)]
public int Human { get; set; }
public IEnumerable<Human> Humans { get; set; }
}
And the GET controller action
[HttpGet]
public ActionResult Create()
{
var model = new CreateDogModel
{
Humans = db.Human.ToList()
};
return View(model);
}
The view then becomes
@Html.DropDownListFor(
model => model.Human,
Model.Humans.Select(h => new SelectListItem
{
Text = h.Name,
Value = h.ID.ToString()
}),
"Please select a Human");
In your POST controller action, you now look up the chosen human by the Human
property value from the View model
[HttpPost]
public ActionResult Create(CreateDogModel model)
{
if (!ModelState.IsValid)
{
// fetch the humans again to populate the dropdown
model.Humans = db.Human.ToList();
return View(model);
}
// create and persist a new dog
return RedirectToAction("Index");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With