So I have my Viewbag that pulls through a dropdown list in my create razor view which uses the follownig Code:
Controller
ViewBag.ActionTypes = new SelectList(query.AsEnumerable(), "ActionTypeID", "ActionTypeTitle");
Then my Razor does this;
#Html.DropDownList("ActionTypeID", (IEnumerable<SelectListItem>)ViewBag.ActionTypes)
I'm stuck on what to put in my Post Method and how to get the value from the dropdown list?
can anyone point me in the right direction
Assuming you have a model called ActionType:
public class ActionType
{
public int ActionTypeID { get; set; }
...
}
Since your SelectList using this same property name, the ModelBinder will take care of setting the correct POSTed value:
new SelectList(query.AsEnumerable(), "ActionTypeID", "ActionTypeTitle");
--------------------------------------------^
Just remember to add a property with the same name to the Model class you're using in your Action:
-------------------------------v Add the property to this class.
[HttpPost]
public ActionResult Create(SomeModel model)
{
}
Here's an example. Imagine you have the following Entities already generated by Entity Framework:
Person Country
------- -------
PersonID CountryID
FullName Name
CountryID
[HttpPost]
public ActionResult Create(PersonModel model)
{
if (ModelState.IsValid)
{
DbEntities db = new DbEntities();
Person person = new Person();
person.FullName = model.FullName;
person.CountryID = model.CountryID; // This value is from the DropDownList.
db.AddToPersons(person);
db.SaveChanges();
return RedirectToAction("Index", "Home");
}
// Something went wrong. Redisplay form.
return View(model);
}
It's just a matter of setting the POSTed ID value to the foreign key property of the entity object.
Related
I'm struggling to conceptualise this because every resource I have found on Google has presented a different way to do it.
I have, at the moment generated razor views pertaining to a scaffolded controller using entity Framework. My controller looks like this:
// GET: tbl_computerinfo
public ActionResult Index()
{
var tbl_computerinfo = db.tbl_computerinfo.Include(t => t.tbl_equipment);
tbl_computerinfo = tbl_computerinfo.Where(c => c.Company == "Company Name");
return View(tbl_computerinfo.ToList());
}
My Model is quite large but is just a generated entity framework model built on two tables linked with a foreign key tbl_computerinfo and tbl_equipment.
There is a string field called company in tbl_computerinfo. I need to select all the unique company values in the database and then use that to populate a dropdown which would exist on the index view. The selection of a company on that dropdown list should then filter the results in index view to only pull back entries with that company name. Any pointing in the right direction would be gratefully appreciated.
You need to create a ViewModel:
public class ComputerInfoViewModel
{
public List<string> CompanyList {get; set;}
public ComputerInfo ComputerInfo {get; set;}
}
In your Index method you populate this and pass it to the View:
public ActionResult Index()
{
var model = new ComputerInfoViewModel
{
CompanyList = /* populate this with your list of companies */
ComputerInfo = /* populate this with what? */
};
return View(model);
}
In your View, you declare the model:
#model ComputerInfoViewModel
And you can access the model properties for display using #Model.CompanyList and #Model.ComputerInfo
my view:
#using (Html.BeginForm("Index", "Person"))
{
#Html.DropDownList("Departments",ViewData["Departments"] as SelectList)
<button type="submit">Select</button>
}
my DepartmentController:
public ActionResult Index()
{
ViewData["Departments"] = new SelectList(db.Departments, "ID", "Name");
return View();
}
my PersonController
public ActionResult Index(string id = null)
{
if (id != null)
{
//Return list of persons with department id
}
return View();
}
My problem:
When I select a department from the DropDown and press the button, it redirects fine, but the id is not passed.
What am I missing? I'm guessing it has to do with how i fill the DropDownList?
Anyway, as always, thanks in advance
The name attribute of your dropdown is not "id" so the MVC model binder can not bind it.
Add html attribute new {#Name ='id'} to your DropDown definition and it should work.
I also would suggest that your view receive a model - in this case model binding will be much easier, and you could use DropDownFor helper.
Using model also allows you to avoid using ViewData and ViewBag containers that are not recommended because they are not strongly typed so if by mistake you write ViewData["Departnents"] in your View you won't get a compilation error because of the typo, but clearly it won't work.
As an opposite you can define a model
public class Person
{
public SelectList Departments {get; set;}
public int SelectedDepatrmentId {get; set;}
//Other person properties come here
}
In your View the only thing you should do to make it work is:
#model path to your Person class
#Html.DropDownListFor(model => model.SelectedDepatrmentId, Model.Departments)
The problem in your case that mvc model binding is done with name attribute and #Html.DropDownList("Departments"... will render html with dropdown having name 'Departments' so either try my first answer or change #Html.DropDownList("Departments"... as shown in my second answer.
Try This :
public ActionResult Index(string Departments) // <------ Use 'Departments' here instead of 'id'
{
.....
return View();
}
OR change dropdownlist as :
#Html.DropDownList("id",ViewData["Departments"] as SelectList)
I'm attempting to use DataBinding in MSMVC using CodeFirst and the Entity Framework. I'm trying to pass a model with a foreign key to the view, edit the data and bind the result back in a controller action before performing an update.
Simply put how do I get Entity to populate the values of foreign key objects at the controller.
The model is very simple and contains only a string 'Text' and the foreign key UserModel 'User'. The BaseModel contains only an Id and a DateTime.
public class CommentModel : BaseModel
{
[Required]
[Display(Name = "Text")]
public string Text { get; set; }
public virtual UserModel User { get; set; }
}
In my Razor view I have a hidden field for the User.Id :
#Html.HiddenFor(model => model.User.Id)
In my controller action I have :
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(CommentModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
_commentsRepository.Update(model);
return RedirectToAction("Index");
}
The problem is that ModelState contains errors as only the Id property of the UserModel is populated?
Can anyone tell me what I'm doing wrong?
Do you have other properties being set via form fields in your view or are you simply passing the ID of the User back for some other reason.
If you are updating other properties of your UserModel in the view then these should be serialized via model binding automatically as long as the naming convention is correct "i.e. ID="User.Id" or ID="User.FirstName"...
i want to show a dropdownList on a page using Entity Framework in my MVC app, but i am just stuck here to do this using using HTML Helper. so if anyone having knowledge of entity framework, help me...
my dataContext partial class is Entities, in which an entity named MemberInfo have some fields including MemberID & MemberName, so my dropdownList should show the field MemberName & behind this the value should be MemberID,
the code i tried yet--->
#Html.DropDownListFor(Model => Model.MemberID, MemberInfo)
in controller i am returning the Model--->
var MemberNameList = FinanceDBContext.MemberInfoes.Select(x => new { x.MemberID, x.Name });
return View(MemberNameList);
but its not working (errors).
You need to pass in all of your objects as the "model". Best practice is to use a ViewModel which will contain the list of data and a property to store the selected item.
ViewModel
public class MyViewModel
{
// The drop-down list and variable to get selection
public List<Member> Members { get; set; }
public int SelectedMemberId { get; set; }
}
Controller
[HttpGet]
public ActionResult Index()
{
var viewModel = new MyViewModel();
viewModel.Members = FinanceDBContext.MemberInfoes.ToList();
return View(viewModel);
}
[HttpPost]
public ActionResult Index(MyViewModel viewModel)
{
string debug = string.Format("You selected member: {0}", viewModel.SelectedMemberId);
return View(viewModel);
}
Finally, in your view (these lines need to be inside a BeginForm { ... } and ensure your View is strongly typed to MyViewModel
#Html.DropDownList("SelectedMemberId", new SelectList(Model.Members, "MemberID", "Name"))
<input type="submit" value="Save etc..." />
In this example you could put a break-point on the HttpPost action and check the debug string to check the correct Member is returned and proceed as required.
I have two related POCOs
public class Parent
{
public Guid Id {get; set;}
public IList<Child> ChildProperty {get; set;}
}
public class Child
{
public Guid Id {get; set;}
public String Name {get; set;}
}
and I have a .cshtml Razor view with
<div>
#{
var children =
new SelectList(Child.FindAll(), "Id", "Name").ToList();
}
#Html.LabelFor(m => m.Child)
#Html.DropDownListFor(m => m.Child.Id, , children, "None/Unknown")
</div>
I'd like to do the following in my controller class:
[HttpPost]
public ActionResult Create(Parent parent)
{
if (TryUpdateModel(parent))
{
asset.Save();
return RedirectToAction("Index", "Parent");
}
return View(parent);
}
Such that if the user selects "None/Unknown", the child value of the parent object in the controller is null but if the user selects any other value (i.e. an ID of a child object retrieved from the database), the child value of the parent object is instantiated and populated with that ID.
Basically I'm struggling with how to persist a list of possible entities across the HTTP stateless boundary such that one of the entities is properly rehydrated and assigned via the default model binder. Am I just asking for too much?
Am I just asking for too much?
Yes, you are asking for too much.
All that's sent with the POST request is the ID of the selected entity. Don't expect to get much more than that. If you want to rehydrate or whatever you should query your database. The same way you did in your GET action to populate the child collection.
Oh and there's a problem with your POST action => you are calling the default model binder twice.
Here are the 2 possible patterns (personally I prefer the first but the second might be useful in some situations as well when you want to manually call the default model binder):
[HttpPost]
public ActionResult Create(Parent parent)
{
if (ModelState.IsValid)
{
// The model is valid
asset.Save();
return RedirectToAction("Index", "Parent");
}
// the model is invalid => we must redisplay the same view.
// but for this we obviously must fill the child collection
// which is used in the dropdown list
parent.ChildProperty = RehydrateTheSameWayYouDidInYourGetAction();
return View(parent);
}
or:
[HttpPost]
public ActionResult Create()
{
var parent = new Parent();
if (TryUpdateModel(parent))
{
// The model is valid
asset.Save();
return RedirectToAction("Index", "Parent");
}
// the model is invalid => we must redisplay the same view.
// but for this we obviously must fill the child collection
// which is used in the dropdown list
parent.ChildProperty = RehydrateTheSameWayYouDidInYourGetAction();
return View(parent);
}
In your code you've made some mix of the two which is wrong. You are basically invoking the default model binder twice.