I have a listboxfor on my view which I populate with a list of users. I can add users to and from this listbox (from another listbox).
I can pass the values back to the contoller but I have to select users in the listbox for this to happen. I don't want to have to select users..just pass back whatever is in the listbox.
On my view:
#Html.ListBoxFor(m => m.SelectedIDs, DropdownHelper.GetGroupMembers(Model.Id), new { size = 20, #class = "select field small", #style = "width:200px" })
In my view model:
public int[] SelectedIDs { get; set; }
The controller HtttPost Edit takes the view model and SelectedIDs does contain the ids for the users, but only when selected.
I just don't want to have to select users in the listbox...just passback whatever values are there.
Any ideas?
Thanks
Someone will correct me if I missed any, but basically you have five options for passing data to the server:
Cookies
QueryString
Ajax
WebSocket
POST (form variables)
It seems like you want to POST data, so to me hidden inputs is the most appropriate way.
Related
While a search of "Default value of DropDownList" produces results, this is not a duplicate question because the specific issue is not listed in the examples and answers I have searched.
Here is the main question first, followed by supporting background and details:
When I place a DropdownList in an Html.BeginForm block, how can I have the default DropDownList values be an item other than the first item in the list?
What I have done so far:
SO, Microsoft Virtual Academy, and a general Internet Search using various search terms, with no effective answers that solve this specific issue.
Looking at the overloads of Html.DropDownList on MSDN. The optionLabel parameter inserts an item at the very top of the list, such as "Select an Item", which is not desired behavior.
jQuery, which does work as intended, but I'm really hoping there is a much simpler way that doesn't involve jQuery.
My Working Theory: The method I learned (and shown below) does not allow for default values and it is not a case of not knowing a particular overload of Html.DropDownList.
Background Info:
In the process of learning MVC 5 and gathering instructions from tutorials and SO answers, I learned this style of creating a DropDownList that is placed within a Html.BeginForm() block in the View. It works, if I want the default value to be the first item in the list or if I want to add an item inserted at the top that says "select an item."
However, there are times when it is meaningful to for the default value to be other than the first in the list.
In the controller, the defaults of the parameter are set Index(string campus = "MRA", string fy = "FY16"), and the query returns the correct result, but DropDownLists are not set accordingly when loading the page for the very first time.
Controller
public ActionResult Index(string campus = "MRA", string fy = "FY16")
{
/* The ViewBags feed DropDownLists used to filter the query */
ViewBag.CampusList = new List<string> { "CRA","DRA","MRA","PRA"};
ViewBag.FyList = new List<string> {"FY15","FY16" };
IEnumerable<AssociatedW3SuspensionOrProbation> query =
db.AssociatedW3SuspensionOrProbation
.Where(m=>m.Campus==campus).Where(m=>m.FY==fy)
.OrderBy(m=>m.StudentName).ThenBy(m=>m.LatestEntryDate);
return View(query.ToList());
}
View
The dropdowns function correctly: when the form is submitted, the query results are chosen by the selected dropdown values and the dropdowns load with the selected values.
#using (Html.BeginForm())
{
<div class="panel panel-default">
<div class="panel-body">
<p>
<strong>Campus</strong>: #Html.DropDownList("campus",
new SelectList(ViewBag.CampusList)) ||
<strong>FY</strong>: #Html.DropDownList("fy",
new SelectList(ViewBag.FyList))
</p>
<div><input type="submit" value="Search" /></div>
</div>
</div>
}
Is there a simple answer to this problem, or does this require a totally different approach?
What you have to do is create SelectList in the controller action and there is a constructor overload which can be used to set selected value, but for that you would need a List<T> which is not string but a custom type that contains 2 properties 1 for TextField and 1 for ValueField.
You have to use second Constructor overload listed here
Here is the example code:
ViewBag.CampusList = new SelectList(
new List<string> { "CRA","DRA","MRA","PRA"},
campus // selected value
);
ViewBag.FyList = new SelectList(
new List<string> {"FY15","FY16" },
,fy // selected value
);
and in your view:
#Html.DropDownList("campus",
ViewBag.CampusList as SelectList)
#Html.DropDownList("fy",
ViewBag.FyList as SelectList)
I have a basic form allowing users to input details which then gets posted and saved to a database - this works as expected without any issues:
#model R32.Register.Models.RegisterCar
#{
ViewBag.Title = "Edit Your R32";
}
<h2>Edit R32</h2>
<div>
#using (Html.BeginForm("UpdateCar", "Garage", FormMethod.Post))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Enter details</legend>
<ol>
<li>
#Html.LabelFor(m => m.NumberPlate)
#Html.EditorFor(m => m.NumberPlate, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.NumberPlate)
</li>
<li>
#Html.LabelFor(m => m.Edition)
#Html.EnumDropDownListFor(m => m.Edition, "Select an edition:", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Edition)
</li>
<li>
#Html.LabelFor(m => m.Colour)
#Html.EnumDropDownListFor(m => m.Colour, "Select a colour:", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Colour)
</li>
</ol>
<input type="submit" value="Save Changes" />
</fieldset>
}
</div>
Model snippet:
[Required]
[Display(Name="Edition")]
public MkEnum? Edition { get; set; }
Enum:
public enum MkEnum
{
[Display(Name="Mk4")]
Mk4 = 1,
[Display(Name="Mk5")]
Mk5 = 2
}
The control renders as expected, with the Edition dropdownlist having three values: "Select an edition", "Mk4", and "Mk5".
The user is able to select an edition, control is validated, then posted to the controller.
The Post is successful, and all selected values are sent to the controller - the app then persists the data in a database, and so on, without any problems.
The issue is when I pass this model back into the same View to allow the user to edit the saved data, the saved values for the enums are NOT being set as the selected value in the dropdownlist.
I can confirm that any saved string values, such as NumberPlate in this example, are being passed back into the view and loaded into the UI.
Putting a breakpoint on the viewmodel as it renders I can confirm that my #model contains the saved values for enum properties - Edition for example - but the end result is that the "Select an edition:" dropdown list is rendered containing the expected dropdown values, but it's value is the default "Select an edition:" instead of the actual value passed in via. m.Edition.
I have been able to get this working using DropDownListFor - but am having difficulties in understanding why this is not working using EnumDropDownListFor, as this clearly seems like a more elegant solution.
Does anyone have any help/advice for this?
I just ran into this problem myself. This happens because fields of type enum are being passed back to the browser serialized as their enum names, but #Html.EnumDropDownListFor generates its option values as integers. The browser can't match up the two so the dropdown stays at its default selection.
There are 3 ways to get around this.
Get the view model's enum field to serialize properly as an int.
Write a dropdown generator that uses enum names as option values.
Use javascript to manually select the option (includes razor syntax here)
$("#YourDropdownID option").each(function () {
if ($(this).html() == '#(Html.DisplayFor(o => o.YourEnumFieldName))') {
$(this).attr("selected", "selected");
return;
}
});
Ok, so from what I could see the problem was caused by using an ActionLink to pass back the full model of an item being edited. Everything was being sent back in a Query string, so my Enum values were being passed to the controller in the following way: mkEnum=Mk4.
I was then loading the UpdateCar view as seen above in my example - but the query string values were being persisted in the call back to the View.
EnumDropDownListFor is unable to interpret/convert the text value of enums into their actual values - if I manually edited the Query string to mkEnum=1, then the correct value wasloaded into the ViewModel.
In addition to this problem, it was not a good solution passing the full model back to the controller.
I've modified the code to pass back a single Id of the item being edited - the controller then verifies the user has access to that Id, retrieves the Model from the Database then passes it back to the same View as in my above example.
With this change my dropdowns are now being updated with their values without any issues.
TLDR; If you experience this issue check to make sure you don't have model properties, specifically enum values represented by their string values, in a query string when loading your view and using EnumDropDownListFor.
In my viewmodel I have a lot of rows. I need the user to select an employee from a dropdownlist for each row. The list of employees to choose from is the same for each row, like this:
#foreach(var item in Model.Rows)
{
#Html.DropDownListFor(m => item.EmployeeID, Model.EmployeeSelectList, "-- Choose --", new {id = "employee_" + item.ID })
...
}
and the model looks something like this:
public class TheViewModel
{
public SelectList EmployeeSelectList {get;set;}
public List<Row> Rows {get;set;}
}
Do I really need to have my SelectList in my Row Class instead to be able to set the selected value without using javascript or am I missing something?
The reason for asking this question is off course that the amount of redundant data sent to the client would be a lot.
As pointed out to me in the comments below, the HTML is rendered at the server anyway so it doesn't matter.
jarvanJiang helped me to clarify this to me as you can see in the conversation under the question. Thank you!
The answer is: It is not possible.
Its because it does not matter as all the HTML is rendered at the server anyway. And each row has the with all its -tags when they are sent to the client. By this time it is not redundant data any more, it is just the screen.
Try this for add extra property in your model and you can get the ddl selected value there !
#Html.DropDownListFor(m => **Model.SelectedValue**, Model.EmployeeSelectList, "-- Choose --", new {id = "employee_" + item.ID })
...
public class TheViewModel
{
public SelectList EmployeeSelectList {get;set;}
public List<Row> Rows {get;set;}
**public int SelectedValue{get;set;}**
}
Now You select any values in your dropdown ,the values had add in the SelectedValue property for
Controller
int selvalue=yourModelObject.SelectedValue;
I'm having a bit of an issue that I'd appreciate some help with.
I have a User object with properties ID and NAME that I need to display in a Readonly textbox. I'd like to populate the texbox's value with ID and Text with Name.
When submitted to Formcollection I need to retrieve entered data with:
collection.Get("User")
I know this is not the correct syntax but I'm trying to achieve the following:
#Html.TextBoxFor(model => model.User, new { #readonly="readonly",#Value = model.Id , #Text=model.Name })
What do I need to do to correct this ? In the textbox how can I display the user Name, when submitted return the user ID with collection.Get("User") ?
Thank you in advance.
p.s.
Standard
#Html.TextBoxFor(model => model.User.Name)
doesn't work for me as it doesn't store the value and
#Html.TextBoxFor(model => model.User, new { #readonly="readonly",#Value = Model.User.Id})
fails for obvious reason when User.Id is empty (in my case it's possible ).
You need to store the Id in a hidden input field.
#Html.HiddenFor(x => x.User.Id)
#Html.TextBoxFor(x => x.User.Name, new { #readonly = "readonly" })
Keep in mind that as long as you use readonly, the value will be model-binded. But as soon as the field is disabled, it won't. So you will receive null values in your Controller.
In the Controller you can use Modelbinding instead of accessing the FormCollection.
public ActionResult Whatever(User user)
{
// user.Id
// user.Name
// should be filled.
}
Update:
Why do you wan't to have those values in the view in the first place?
If you need them for modelbinding you should be aware that people are still able to manipulate them even though they are readonly (Firebug, POST requests from other scripts).
If you require them for your model to be valid I would recommend using hidden input fields. And on the server side make sure that you only save values that the user is actually supposed to change.
I don't know how to exactly have Cascading DropDownLists
My scenario is the next:
Category has Items and Items have quantities depending on Establishment
I want to have two DropDownLists one which you select a Category, next one is populated when you make a selection of the first with the Items in that Category, and when you select the Item a table with the quantities for each establishment is shown.
Ok this would be my ActionResult
public ActionResult ItemByClinic(Guid? Item_ID, Guid? Category_ID)
{
ViewData["Categories"] = InventoryDb.Categories;
if (Category_ID != null)
{
ViewBag.Category_ID = Category_ID;
ViewData["Items"] = InventoryDb.Items.Where(i => i.Category.ID == Category_ID);
if (Item_ID != null)
{
ViewBag.Item_ID = Item_ID;
ViewData["Inventory"] = InventoryDb.Items.Single(i => i.ID == Item_ID).Inventory;
}
}
return View();
}
then, I would have my two DropDownLists that should post values to Item_ID and Category_ID ... first category then item
#Html.DropDownList("Categories", new SelectList((IQueryable<Inventario_Data.Models.Category>)ViewData["Categories"], "ID", "Name", ViewBag.Category_ID), "Select an Item Category", new { onchange = "window.location.href = '/Inventory/ItemByClinic/Categody_ID=' + this.value" })
This is what I don't know how to do ... how should I put the URL or how should I send it, so when I send the other ID does'nt mix up and I can receive my IDs
How do I receive the values of each DropDownList in the ActionResult? how should they be sent?
ANSWER
I found the answer from this website, just wanted to let know what I did
http://kmsystems.squarespace.com/journal/2009/5/31/aspnet-mvc-cascading-dropdownlists.html
The way you are describing your problem sounds like you are trying to do too many things at once.
To make it easier to explain, I'm going to use the Country / State lookup use case. (When I select "Country", the "State" drop down is populated.)
You have 4 elements:
Initial form load (no country, no state selected)
Country selected, State populated
Country selected, State selected
Error handling (invalid Country & State combination)
When I have come across this, I handle Step 1 & 3 in a view similar to your example.
So are you getting stuck on step 2? What do you mean when you say " how should I put the URL or how should I send it,"
For me, I'll address step 2 by creating javascript controller and use jquery to post & return json objects triggered when the Country dropdown box is selected.
I found the MVC Music Store and Nerd Dinner examples to be extremely helpful.
If you need an example of the json / jquery, see the shopping cart in The Music Store example.