I am sorry if I ask a newbie question but i am new to asp.net mvc.
So, I have this view :
#model FirstProject.Models.SelectRolesViewModel
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm("SelectRolesOverall","SelectRoles"))
{
<table class="table">
<tr>
<th>Users</th>
<th>Roles</th>
</tr>
#Html.EditorFor(model=>model.UsersAndRoles)
<tr>
<td></td>
<td>
<input type="submit" />
</td>
</tr>
</table>
}
And the EditorTemplate :
#model FirstProject.Models.UserRole
<tr>
<td>#Model.User.UserName</td>
<td>
#Html.RadioButtonFor(model => model.Role, "Applicant") Applicant
<br/>
#Html.RadioButtonFor(model => model.Role, "Professor") Professor
</td>
</tr>
My question is next : How do I see what radio buttons have been checked in my controller after the submit button has been pressed? I want to have the following logic : If Applicant have been selected then userRole is Applicant , else if Professor has been selected then userrole is Professor. My controller is Empty momentarily because I don't know what to write in it.
If your action method is
public SelectRolesOverall(SelectRolesViewModel model)
then you can access the collection with
IEnumerable<UsersAndRoles> usesAndRoles = model.UsersAndRoles;
and access each item in the collection
foreach (UserRole userRole in model.UsersAndRoles)
{
string role = userRole.Role;
string name = userRole.UserName; // see note below
}
Note you have not included an input for the property UserName so this value wont post back and you might have trouble matching the role to the user. You might want to add #Html.HiddenFor(m => m.UserName) or change <td>#Model.User.UserName</td> to <td>#Html.TextBoxFor(m => m.UserName, new { #readonly = "readonly" })</td>
Try this
public ActionResult [YourActionName](string role)
{
switch(role){
case "Applicant": /*your applicant logic*/
break;
case "Professor": /*your Professor logic*/
break;
/*
Other logic here
*/
}
Replace the action name by your own
Note that the parameter role should have the same name of the radio button in your view, this is to allow data binding to work
Related
From the menu page a user clicks an "Add to Order" button. The "Add to Order" button triggers the addToOrder function. That function works correctly, the drink is passed and an order is created with the drink information. After clicking the "Add to Order" button the user is sent to a confirmation page where their drink order is displayed and takes in their name in a form. The information passes correctly to the confirmation page, however when the form on the confirmation page is submitted the drink information is not passed but the rest of the form is. Any suggestions on how to get the drink information to pass in the object is greatly appreciated!
In the Home Controller:
From the menu page, this gets the drink information and works correctly:
[HttpGet]
public ActionResult addToOrder(int id)
{
Drink drinkToAdd = _drinkRepository.GetDrink(id);
List<Drink> dList = new List<Drink>();
dList.Add(drinkToAdd);
Order order = new Order();
order.drinkList = dList;
order.total = drinkToAdd.drinkPrice;
ViewData.Model = order;
return View("OrderConfirmation");
}
This method gets the information from the form in the order confirmation page:
[HttpGet]
public ActionResult confirmedOrder(Order order, int drinkID)
{
Drink drinkToAdd = _drinkRepository.GetDrink(drinkID);
List<Drink> dList = new List<Drink>();
dList.Add(drinkToAdd);
order.drinkList = dList;
_orderRepository.Add(order);
return View("ThankYou");
}
This is the order confirmation page:
#model BartenderApp.Models.Order
#{
ViewData["Title"] = "Order Confirmation";
}
<html>
<body>
<h1>Order Confirmation</h1>
<form asp-action="confirmedOrder" method="get" >
<p>#Html.DisplayNameFor(m => m.FirstName): #Html.TextBoxFor(m => m.FirstName)</p>
<p>#Html.DisplayNameFor(m => m.LastName): #Html.TextBoxFor(m => m.LastName)</p>
<table class="table">
<thead>
#foreach (var item in Model.drinkList)
{
<tr>
<td>
#Html.HiddenFor(modelItem => item.id)
</td>
<td>
<b>#Html.DisplayNameFor(modelItem => item.drinkName)</b>
</td>
<td>
<b> #Html.DisplayNameFor(modelItem => item.drinkDescription)</b>
</td>
<td>
<b> #Html.DisplayNameFor(modelItem => item.drinkPrice)</b>
</td>
</tr>
}
</thead>
<tbody>
#foreach (var item in Model.drinkList)
{
<tr>
<td>
#Html.HiddenFor(modelItem => item.id, new { drinkID = item.id } )
</td>
<td>
#Html.DisplayFor(modelItem => item.drinkName)
</td>
<td>
#Html.DisplayFor(modelItem => item.drinkDescription)
</td>
<td>
#Html.DisplayFor(modelItem => item.drinkPrice)
</td>>
</tr>
}
</tbody>
</table>
<p style="float:left">#Html.ActionLink("Modify Order", "Menu")</p>
<p style="float:right"><b>#Html.DisplayNameFor(m => m.total):</b> $#Html.DisplayFor(m => m.total)</p>
<input type="submit" value="Checkout" name="checkout" style="float:right" />
</form>
</body>
</html>
When I hit the submit button on the form I thought the entire object would pass but only the first and last name are. I have tried to then pass the specific drinkID so I could locate it in the repository and add it to the order. However, the drinkID is not passing either (always 0). Why is the drink information not passing with the rest of the object?
Thanks
This is the URL after I hit the submit button on the order confirmation page:
https://localhost:44378/Home/confirmedOrder?FirstName=John&LastName=Jones&item.id=1&item.id=1&checkout=Checkout
In this example, I did add the drink with the ID of 1 to my order. There is also another order in the repository, so the ID of the order is 2.
I would like to be able to press a submit button in my Index view which saves all the changes made to the list through the EditorFors that I use.
In the Edit View I can edit and save one list item at a time, but I would like to be able to save the full list in one click.
I've tried wrapping the whole table in the Index view with #using(Html.BeginForm()) {}, then added an HttpPost method in the controller like this:
[HttpPost]
public ActionResult Index(List<TileModel> modelList) {
return View(modelList);
}
But modelList is null when I enter this method. I've tried adding [Bind("MyModel")] to the parameter list but I'm a bit clueless as what to bind ..
I'm basically trying to copy the functionality of this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "ID,Name,Employment")] TileModel mModel) {
if(ModelState.IsValid) {
db.Entry(mModel).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(mModel);
}
, but have it save the full list while inside the Index view.
Any ideas how one could achieve this? Am I even remotely on the right track?
Edit:
Here's my index view(my edit view is basically unchanged from what visual studio generates so I don't think it's that interesting to show?).
#model IEnumerable<Anslagstavlan.Models.TileModel>
#{ ViewBag.Title = "title"; }
<ul class="nav navbar-nav">
<li>#Html.ActionLink("TILES", "tileboard", "tilemodels")</li>
<li>#Html.ActionLink("NEW ENTRY", "Create")</li>
</ul>
#using(Html.BeginForm()) {
<table class="table">
<tr>
<th> #Html.DisplayNameFor(model => model.Name) </th>
<th> #Html.DisplayNameFor(model => model.InfoFields) </th>
<th> #Html.DisplayNameFor(model => model.Employment) </th>
<th></th>
</tr>
#foreach(var item in Model) {
<tr>
<td> #Html.DisplayFor(mItem => item.Name) </td>
<td> #Html.EditorFor(mItem => item.InfoFields, new { htmlAttributes = new { #class = "form-control" } }) </td>
<td> #Html.DisplayFor(mItem => item.Employment) </td>
<td>
#Html.ActionLink("SAVE", "Save", new { id = item.ID }) |
#Html.ActionLink("EDIT", "Edit", new { id = item.ID })
</td>
</tr>
}
</table>
<input type="submit" value="Save" class="btn btn-default" />
}
Edit2, working:
My loop with the table now looks like:
#using(Html.BeginForm()) {
<table class="table">
#for(int i = 0; i < Model.Count; i++) {
<tr> <td>
#Html.TextBoxFor(m => m[i].Name)
</td> </tr>
}
</table>
<input type="submit" value="Save" class="btn btn-default" />
}
The only difference from Stephens answer is the # sign before the for loop..
Change the model in the view to be IList<TileModel> and generate the controls in a for loop so they are correctly named with indexers and can be bound to a collection on post back
View
#model IList<Anslagstavlan.Models.TileModel>
#using(Html.BeginForm())
{
....
for(int i = 0; i < Model.Count; i++)
{
#Html.TextBoxFor(m => m[i].InfoFields, new { #class = "form-control" })
.... // controls for other properties of your model that you want to post back
}
<input type="submit" value="Save" class="btn btn-default" />
}
POST method
[HttpPost]
public ActionResult Index(List<TileModel> modelList)
{
// save each item and redirect
}
how can i get the querystring id in there? is there any way
#using (Html.BeginForm("InformVendor", "Procurement",new {id="querystring Mode = "Inform" }, FormMethod.Post))
{
<tr>
<td>
#Html.DropDownListFor(m=>m.VendorId,new MultiSelectList(Model.VendorDropdownlist, "CustomerId", "ContactName"))
</td>
<td>
#Html.CheckBoxFor(m => m.IsEmail)
</td>
</tr>
<tr>
<td>
<input type="submit" id="btnsubmit" value="Nominate Vendor" />
</td>
<td></td>
</tr>
}
The easiest way is to have your id field be hidden. This way the user doesn't see the ID field but your post back controller does.
#Html.HiddenFor(x => x.YourID)
If you add the Id to your view model and render it as a hidden field.
#Html.HiddenFor(m => m.Id)
You will be able to retrieve it like this instead of using the querystring.
public ActionResult InformVendor(AViewModel model)
{
var Id = model.Id;
}
I have recently started playing around with ASP.net MVC (4), but I can't wrap my head around this one issue I'm having. I'm sure it's easy when you know it.
I'm essentially trying to do the the following in my Index view:
List the current items in the database of type "Note" in the Index view (that's easy)
Creating new items in the same Index view (not so easy).
So I figured I needed a partial view, and that I have created as following (_CreateNote.cshtml):
#model QuickNotes.Models.Note
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Note</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Content)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Content)
#Html.ValidationMessageFor(model => model.Content)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
In my original Index view (Index.cshtml) I'm trying to render this partial view:
#model IEnumerable<QuickNotes.Models.Note>
#{
ViewBag.Title = "Personal notes";
}
<h2>Personal notes</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.Content)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Content)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
#Html.ActionLink("Details", "Details", new { id=item.ID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ID })
</td>
</tr>
}
</table>
<div>
#Html.Partial("_CreateNote")
</div>
(using: #Html.Partial("_CreateNote"))
However. This doesn't seem to work, as I get the following error message:
Line 35:
Line 36: <div>
Line 37: #Html.Partial("_CreateNote");
Line 38: </div>
Source File: c:\Dropbox\Projects\workspace .NET MVC\QuickNotes\QuickNotes\Views\Notes\Index.cshtml Line: 37
Stack Trace:
[InvalidOperationException: The model item passed into the dictionary is of type 'System.Data.Entity.DbSet`1[QuickNotes.Models.Note]', but this dictionary requires a model item of type 'QuickNotes.Models.Note'.]
System.Web.Mvc.ViewDataDictionary`1.SetModel(Object value) +405487
My NotesController looks like this:
public ActionResult Index()
{
var model = _db.Notes;
return View(model);
}
//
// GET: /Notes/Create
public ActionResult Create()
{
return View();
}
//
// GET: /Notes/_CreateNote - Partial view
public ViewResult _CreateNote()
{
return View("_CreateNote");
}
I think it has to do with the fact that the Index view is using the model differently, as in #model IEnumerable, but no matter how I change it around, using RenderPartial, RenderAction, changing ActionResult to ViewResult etc, I can't get it to work.
Any tips would be greatly appreciated!
Please let me know if you need any more information. I'd be happy to zip down the entire project if needed.
Change the code where you load the partial view to:
#Html.Partial("_CreateNote", new QuickNotes.Models.Note())
This is because the partial view is expecting a Note but is getting passed the model of the parent view which is the IEnumerable
You're passing the same model to the partial view as is being passed to the main view, and they are different types. The model is a DbSet of Notes, where you need to pass in a single Note.
You can do this by adding a parameter, which I'm guessing as it's the create form would be a new Note
#Html.Partial("_CreateNote", new QuickNotes.Models.Note())
This question already has an answer here:
How to pass IEnumerable list to controller in MVC including checkbox state?
(1 answer)
Closed 6 years ago.
All, please clear up my confusion on how the model binding works with IEnumerables and Editor Templates.
I have a view, Approve.cshtml
#model IEnumerable<MvcWebsite.Models.Approve>
<table>
<tr>
<th>
Name
</th>
</tr>
#Html.EditorForModel()
</table>
A model, Approve.cs
public class Approve
{
public string Name { get;set;}
public string Role { get; set; }
}
And an editor template
#model MvcWebsite.Models.Approve
#using (Html.BeginForm("Approve", "Registration", FormMethod.Post))
{
<tr>
<td>
#Html.HiddenFor(m => m.Name)
#Html.EditorFor(m => m.Role)
</td>
<td>
<input type="submit" value="Approve" class="submit-button" />
</td>
</tr>
}
This is all fine and good. It renders the following output.
<input name="[0].Name" type="hidden" value="" />
....
However, in my Controller, I can't seem to receive values back for the Model (binding).
[HttpPost]
public ActionResult Approve(Approve approveModel)
{
.... approveModel has all default values
}
Can someone shed light on what I am doing wrong here? I abbreviated the code, I am using the Editor Template with other EditorFor and HiddenFor fields from my model...
Edited: I basically have a table layout, each with the User's Name, a textbox where I can enter their role (User or Admin) and then an Approve button which submits to my controller. Hence the reason I want to only return a single Approve object. I can return the entire IEnumerable to my Controller, but if I do that, how can I tell which of the items was the one I clicked the Approve button (submit) for?
EDIT:
So I have modified the code so that I have a single form surrounding my entire View Approve.cshtml
#model IEnumerable<MvcWebsite.Models.Approve>
#using (Html.BeginForm("Approve", "Program", FormMethod.Post))
{
<table>
<tr>
<th>
Name
</th>
</tr>
#Html.EditorForModel()
</table>
}
And then changed the controller to
[HttpPost]
public ActionResult Approve(IEnumerable<Approve> approvals)
{
// ???????????????????????
}
Now I'm still not clear on how to know which row I clicked Approve for. I know there are other ways to accomplish this task (create a checkbox for approve, and approve anything checked, etc.) However, I need the ability to click a button and only save 1 row back to the database, regardless if the user entered information into the other rows. Is it better practice to wrap my IEnumerable inside of it's own model (i.e. AllApprovals) and then add helper properties to that parent model (SelectedIndex, etc.)? If that is the approach to take, then how do I set the SelectedIndex after clicking an Approve button? Is that still jquery magic or is there a correct MVC way to accomplish this? Jquery magic seems very hackish to me?
EDIT: Based on Brian's response, here is my final. Still doesn't feel quite right, but it works!
View
#model IEnumerable<MvcWebsite.Models.Approve>
<table>
<tr>
<th>
Name
</th>
</tr>
#Html.EditorForModel()
</table>
Editor Template
#using (Html.BeginForm("Approve", "Registration", FormMethod.Post))
{
<tr>
<td>
#Html.HiddenFor(m => m.Name)
#Html.EditorFor(m => m.Role)
</td>
<td>
<input type="submit" value="Approve" class="submit-button" />
</td>
</tr>
}
Controller
[HttpPost]
public ActionResult Approve([Bind(Prefix="approval")]Approve approval) {
// WORKS!
}
Since you are only changing one at a time, I think the following is easier than trying to figure out at the controller which values changed, or adding a changed property and setting it via javascript.
Change Approve.cshtml to
#model IEnumerable<MvcWebsite.Models.Approve>
<table>
<tr>
<th colspan=2>
Name
</th>
</tr>
#foreach(var user in Model){
#using (Html.BeginForm("Approve", "Registration", FormMethod.Post)) {
<tr>
<td>
#Html.EditorFor(m => user)
</td>
<td>
<input type="submit" value="Approve" class="submit-button" />
</td>
</tr>
}
}
</table>
Change the Approve Editor Template to
#Html.HiddenFor(m => m.Name)
#Html.EditorFor(m => m.Role)
You're binding to the single Approve class, you should bind to IEnumerable<Approve>
Martin is correct I just want to add some more information. Your rendered HTML with the [0] is special syntax the model binder looks at and assumes you are working with a list if objects. Since your action method has a single Approve class and not a kist, you are experiencing this problem.