View
<input type="hidden" name="selectedValue" value="0" />
<select name="itemType" id="itemType" style="width:80%;">
<option value="Item1">Item 1</option>
<option value="Item2">Item 2</option>
<option value="Item3">Item 3</option>
<option value="Item4">Item 4</option>
<option value="Item5">Item 5</option>
</select>
ViewModel
public ItemTypes itemType { get; set; }
Enum List in ItemTypes.cs (Extension Method)
public enum ItemTypes
{
Item1,
Item2,
Item3,
Item4,
Item5
}
public static string GetItemDesc(this ItemTypes itemtype)
{
switch (itemtype)
{
case ItemTypes.Item1:
return "Item 1 Description";
case ItemTypes.Item2:
return "Item 2 Description";
case ItemTypes.Item3:
return "Item 3 Description";
default:
return "Item 4 and 5 Description";
}
}
Above is my code. I would like to retain the selected Enum value throughout the page. I have four, The Index (where the drop down menu lives), the page where you select your payment method, the verification page, (where you verify all the information you put in) and the receipt page (to show that your transaction has been successful.) I need the enum value to remain the same through each page. Please help.
It looks to me like what you need to do is to save the selection somewhere, so the other pages can access that selection. MVC is stateless, so the value needs to either be passed along in each call, or it needs to be saved where the other pages can access it. There are several approaches you could take to save and retrieve selections of browser controls.
Keep in mind that enums will serialize to an integer by default, so when dealing with the value on the client-side, it will be an integer. What this means is that on your view, you likely need to use <option value="0">Item 1</option> using 0, 1, 2, 3, and 4 as your client-side values - or use the MVC HTML helpers or Razor markup, depending on your MVC version, to have those options generated for you using the enum names.
Here are some saving/retrieving options that may fit your needs:
Pass the selection value as a property of the posted content (your itemType) when you submit each page, then when you load the next page, include the value in the query string, or as part of the route for the next get request (GetPaymentMethodPage, GetVerifyPage, GetReceiptPage).
Save the selection value in a cookie, and retrieve it from that cookie in JavaScript (you'll need to provide a default if the cookie doesn't exist, was deleted, or the user doesn't allow cookies).
Save the selection value in browser storage - there are various kinds including Web Storage (SessionStorage or LocalStorage).
You have a few different options but keep in mind that MVC is stateless. This means that MVC is ignorant of any information that was stored in your enums across page requests. Therefore, you need to pass parameters into your action method that receives the enum as a string, then parse the string back into an enum type. An example of how you can do this is here.
Or the copy+pasted code:
using System;
[Flags] enum Colors { None=0, Red = 1, Green = 2, Blue = 4 };
public class Example
{
public static void Main()
{
string[] colorStrings = { "0", "2", "8", "blue", "Blue", "Yellow", "Red, Green" };
foreach (string colorString in colorStrings)
{
try {
Colors colorValue = (Colors) Enum.Parse(typeof(Colors), colorString);
if (Enum.IsDefined(typeof(Colors), colorValue) | colorValue.ToString().Contains(","))
Console.WriteLine("Converted '{0}' to {1}.", colorString, colorValue.ToString());
else
Console.WriteLine("{0} is not an underlying value of the Colors enumeration.", colorString);
}
catch (ArgumentException) {
Console.WriteLine("'{0}' is not a member of the Colors enumeration.", colorString);
}
}
}
}
There is also the fact that any page you want that enum to be accepted by will need to be passed the enum from the action method that generates the view. Then in the view itself, you have to accept and store the enum inside a hidden field.
Related
I'm building an MVC web application and am about to run my head through the wall, there's a dozen topics on this already and all have accepted solutions that do not work for me. There's probably something really stupid and simple I'm forgetting/not seeing, but can't seem to work it out.
Please don't hate me for naming; I'm continuing a project started by someone else.
I have the following line in my ManageDetail.cshtml:
#Html.DropDownListFor(m => m.ChecklistWaarde.SoortID, Model.ChecklistOptionsOptions, "Choose a value", new { #class = "form-control" })
This builds a selectbox based on property Model.ChecklistWaarde.SoortID, which is an integer. The next parameter passed is a SelectList from the model that is generated by the following very simple helper function that does a DB lookup in a 2ndary database (unfortunately), it receives the parameter SoortID as well to set a preselect value:
public SelectList GetChecklistOptions(int selectedId = -1)
{
var soorten = new List<SelectListItem>();
try
{
using (var connection = new SqlConnection(mssqlConnectionString))
{
connection.Open();
SqlCommand command = connection.CreateCommand();
command.CommandText = "Select Naam, ID From ChecklistSoorten";
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
var id = reader["ID"] as int?;
if (id.HasValue)
{
soorten.Add(new SelectListItem { Text = reader["Naam"] as string, Value = id.Value.ToString(), Selected = id.Value.Equals(selectedId) });
}
}
}
}
catch (Exception ex)
{
Globals.Log.Error(ex);
}
return new SelectList(soorten, "Value", "Text");
}
It gets called in the controller like this:
public ActionResult ManageDetail(int? id) {
var model = new MachineDetailsModel(id);
model.ChecklistOptionsOptions = sqlDal.GetChecklistOptions(model.ChecklistWaarde.SoortID);
return View("ManageDetail", model);
}
When I try to debug my code, I can see that the model values are populated correctly:
SoortID has a value of 2 (int)
Model.ChecklistOptionsOptions has a populatedSelectList
Upon inspecting the SelectList I find that only item with value "2" has property Selected = true, this is false for all others.
When the form gets rendered, it will not select the item with value 2, rather it will have the first item selected, "Choose a value"
Inspecting the HTML, I see that the item with value 2 is indeed not selected, contrary to what I was expecting (see HTML below; shorted the list in count and text for readability). I expected to see "selected" on the line for item 2, as it was selected in the SelectList.
<select class="form-control" data-val="true" data-val-number="The field SoortID must be a number." data-val-required="The SoortID field is required." id="ChecklistWaarde_SoortID" name="ChecklistWaarde.SoortID" style="min-width:100%;">
<option value="">Choose a value</option>
<option value="1">Item A</option>
<option value="2">Item B</option>
<option value="3">Item C</option>
<option value="4">Item D</option>
</select>
What am I missing? How can I make item with value "2" select, as it is in the SelectList that I pass to the DropDownListFor() function?
In the controller where you are populating SelectList, set selected value there, your code would look like:
if (id.HasValue)
{
soorten.Add(new SelectListItem
{
Text = reader["Naam"] as string,
Value = id.Value.ToString()
});
}
and then down at the line of instantiating SelectList:
return new SelectList(soorten, "Value", "Text",selectedId);
or you could elminate SelectList and instead in your model change the property ChecklistOptionsOptions type to List<SelectListItem>, in that case the last line of creating SelectList will not be required further, right now you are creating it multiple times.
Ultimately everything in the view that gets rendered comes from ViewData. This takes the model, but also request data and 'ModelState`.
I have had this sort of problem when some of the request parameters have a name conflict with some of the model parameters. This overrides the value in the model and causes the issue.
It is very difficult to debug, as it normally appears that all the correct values have been set. Check all your parameter names if in doubt.
I was using asp-items="#Html.GetEnumSelectList(typeof(Salary))" in my Razor view with a select tag, to populate the list values based on the enum Salary.
However, my enum contains some items which I would like to have spaces within. E.g. one of the items is PaidMonthly, but when I display this using Html.GetEnumSelectList, I would like it to be displayed as "Paid Monthly" (with a space in it)
I tried using the Description attribute over each member in the enum, however when the select box renders it uses the raw value only.
Can anyone please help me out with this matter?
(My Code sample) -> Using ASP.NET Core 1.0
Razor View:
<select asp-for="PersonSalary" asp-items="#Html.GetEnumSelectList(typeof(Enums.Salary))">
</select>
Enum Salary:
public enum Salary
{
[Description("Paid Monthly")]
PaidMonthly = 1,
PaidYearly = 2
}
I managed to solve it. I just had to use the other method of GetEnumSelectList<>, and in the Razor view we need to use the Display attribute.
Here is the code:
Razor View:
<select asp-for="PersonSalary" asp-items="Html.GetEnumSelectList<Enums.Salary>()"></select>
Enum Salary:
public enum Salary
{
[Display(Name="Paid Monthly")]
PaidMonthly = 1,
PaidYearly = 2
}
I have a model with one of the property of type object . This property is a dynamic property and could sometime contain a string or a date or a Boolean.
I have a editor template for each type i.e boolean , string , date etc .
The problem I have is when the page is posted , the postback contains a array instead of the actual value. The first element of the array contains the actual value.
Why is the value being returned as a array ?
My model
public string Description;
public string Name { get; set; }
public Type Type{ get; set; }
object _value;
public object Value { get;set;}
statement in the view
#Html.EditorFor( m => m.Value)
Edit : Corrected the object name from _value to Value. It was a wrong Ctrl V operation.
Edit : The HTML rendered in the browser
When the object contain a boolean value (checkbox):
<div>
<input checked="checked" data-val="true" data-val-required="The BoolJPY field is required." id="FurtherInformationFieldObject_Properties_1__Value" name="FurtherInformationFieldObject.Properties[1].Value" type="checkbox" value="true"><input name="FurtherInformationFieldObject.Properties[1].Value" type="hidden" value="false">
When the object contains a string(Textbox) :
<div id="divStringField"><input class="text-box single-line valid" data-val="true" data-val-required="The String Field field is required." id="FurtherInformationFieldObject_Properties_2__Value" name="FurtherInformationFieldObject.Properties[2].Value" type="text" value=""> </div>
Edit 2 : Posting the complete model and view code.
Controller code :
public ActionResult Edit(string name ="field1" )
{
Models.DynamicData data1 = new Models.DynamicData();
//all this comes from the database table. I am putting the value directly in field just for simplicity
// this is exactly how I convert the value from the entity to the model
data1.Description = "Field1 Description";
data1.Name = "field1";
data1.Type = typeof(string);
data1.Value = Convert.ChangeType("MyStringValue", data1.Type);
//similarly add few more fields to the model collection
return View(data1);
}
[HttpPost]
public ActionResult Edit(Models.DynamicData model)
{
// break point here : model.Value shows a array of string instead of the edited value.
return View(model);
}
View :
#model SampleDynamicDataProject.Models.DynamicData
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>DynamicData</legend>
<div class="editor-label">
#Model.Description
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Value)
#Html.ValidationMessageFor(model => model.Value)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
I should explain I used object as type for Value property because the value could be string or bool or date ex data1 in above controller could look like below
data1.Description = "Field2 Description";
data1.Name = "field2";
data1.Type = typeof(bool);
data1.Value = Convert.ChangeType("true", data1.Type); // database stores "true" as string which is converted into a boolean and stored in the object.
As shown in the code , my problem is in the post action for Edit , I get Value as an array even for a simple string.
The sample project code here https://drive.google.com/file/d/0B3xCaeRk2IQZSTM0aHdoWEtNYW8/edit?usp=sharing
I got a answer to my question at one of the other forums.
Basically the reason MVC binder is returning a array is because it does not understand what type of data/control is used in the html and the model binder fails.
I got around my issue by modifying the model to have two different property a
public String StringValue
public Bool BooleanValue
I use the StringValue field when the Type is String , Date , Number etc.
I use the BooleanValue for field with Type as Boolean.
Its not the cleanest approach but it will have to do till the point I write my own custom model binder.
Thanks to bruce who answered my question here http://forums.asp.net/p/1961776/5605374.aspx?Re+MVC+4+Postback+returns+a+array+for+property+of+type+object+in+my+model
I now understand why the model binder fails.
Pasting his answer here for the benefit of others
you need to understand how browser postback is done. on form submit a collection of name/value pairs is sent. the name is the form element name, the value is the elements value. standard url encoding is done. so for:
the postdata is
foo=1&bar=true
note the post data is just a string with no type data. the brwser allows duplicate name, so
the post data is:
foo=1&foo=true
when asp.net load the post data into the form collection (which is just a dictionary), it can not add the key "foo" twice, but concats the values seperated by a "," ("1,true"). the binder just treats it as a string array named foo with 2 values.
now we get to another browser behavior. form elements that support checked (radio and checkbox) are only include the post data if checked. this causes a problem for the mvc binder with checkbox, becuase it can not tell from the postback data if the element was not checked or not included. this is important if you are using tryupdate to apply only a subset of the model properties, becuase only a subset was rendered. to get around this, the checkbox helper renders two fields with the same name, a hidden with the value "false" and a checkbox with the value "true".
I have Gender attribute as tiny int in Db for employee. When user create new employee i want him to choose male/female (which is working properly) by clicking on radio button. Everything is working fine (create and edit) but i want to display in form (for index, details and delete) not 1 or 2, but male/female. there should be some if statement in view but i'm not sure where to put it or how to write correct one ...
any idea?
Thanks!
this is part of code from model:
This one is from details.cshtml:
If you want to avoid having extra properties on your model or adding stuff to your viewbag you can write it inline using razor syntax like below..
<div class="display-field">
#if (model.GENDER == 0){ #Html.Raw("Male") }
#else if (model.GENDER == 1){ #Html.Raw("Female") }
</div>
That's off the top of my head so you might need to check the exact syntax but i think that's close. It will also just dump "Male" or "Female" inside the div, you might want to put it in a label or p tag at least.
This however isn't the approach I would use in a production app, throughout the code i would use a gender enum to give meaning to your bit value and extend enum to include a description that you can parse for presentation purposes.
I think from what u have said u can write it inline using the razor syntax like below in ur details.cshtml
<div class="display-field">
#if(model.GENDER ==0)
{
<label>Male</label>
}
else if(model.Gender==1)
{
<label>Female</label>
}
</div>
I think this must be enough for displaying the Gender in details page.plz comment if u need any help
Use a condition ? true : false selector
int gender = 1; // assumed male
String genderDesc = (gender == 1) ? "Male" : "Female";
You Could Make this a Drop Down field? In your controller do:
ViewBag.Gender = new[]
{
new SelectListItem { Text = "Male", Value = "1" },
new SelectListItem { Text = "Female", Value = "2" }
}.WithEmpty();
The WithEmpty() will give you a blank option or without it will select the top one.
#Html.DropDownListFor(m=> m.Gender, (Ienumarable<SelectListItem>)ViewBag.Gender);
This way the user will see Male and Female but the value will be bound to your model using the value which is 1 or 2.
I'd advise that you create a ViewModel class to represent the Employee entity in a View-friendly format decoupled from your database model and present it in a strongly typed view so you can return it from the controller.
Hint: Have the Gender property represented as a string in the ViewModel and do the conversion from byte to the string representation in your controller
You may put the code in your controller as e.g:
public ActionResult EmployeeDetails(int id)
{
//retrieve the entity from the DB
//set other employee properties here.
//I'm assuming you have set males to 2 and females to 1
...
employeeViewObject.Gender = employeeObjectFromDB.Gender.Value==2?"Male":"Female";
return View(employeeObjectFromDB);
}
Your strongly typed view will not have trouble displaying the gender while saving you the dirt of mixing code and mark-up as:
<p>model.Gender</p>
or
Html.DisplayFor(model=>model.Gender)
Hi I am quiet new on MVC 3 with C#. I am using entity framework and database first approach to generate code automatically. But the problem is, I tried to find information about inserting checkboxes in MVC3 using C# code but I could not get helpful website.
I can insert the check box using HTML tags:
<input type="checkbox" name="Science" id="s1" value="Science" />
<input type="checkbox" name="Biology" id="b1" value="Biology" />
<input type="checkbox" name="Chemistry" id="c1" value="Chemistry" />
But how do I insert the check box value inside the database and validate that only one single checkbox is selected?
e.g I have a table named Paper where I have:
Paper_Title - textbox
Paper_Details - textbox
Category - Checkboxes (e.g. Science, biology, chemistry)
Comments - textbox.
Submit-button
Use radio button and then have an enum for Categories(say enumCategories). Have a model Category of type enumCategories and then in the postback set the model based on which radio button is checked.
Hope this gives you an elaborate idea on the approach.
I don't think that checkboxes are what you need here, they're more used for multi-selectable items. Either radio buttons or a dropdown would be better suited. Personally, I'd say a dropdown is better for you as there's already an editor template built for it, example:
Model:
I have added the following to properties
public string Category { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
In the load method I have put two sample categories in there:
Categories = new List<SelectListItem>
{
new SelectListItem
{
Selected = false,
Text = "Chemistry",
Value = "Chemistry"
},
new SelectListItem
{
Selected = false,
Text = "Science",
Value = "Science"
}
};
View:
#Html.DropDownListFor(m => Model.Category, Model.Categories)