How to disable #html.dropdownlist option label in .NET? - c#

View Markup :
#Html.DropDownListFor(model => model.entityType, ViewBag.entityType as SelectList, "Select Type", new { #class = "custom-select"})
This is the dropdown list in .NET and "select Type" is the option label.
My expectation : I want to disable "Select Type" option label. how can I do this ?
Thanks in advance who's help me.
Regards:
PHioNiX

My expectation : I want to disable "Select Type" option label. how can
I do this ?
Well,it can be implemented using couple of ways. However, the most easiest and efficient way is, we would check SelectList by its class name in your scenario it would be #class = "custom-select" and set the property as we expect here, disable to be more specific. Just like below:
$('.custom-select option:contains("Select Type")').attr("disabled", "disabled");
Note: Here, .custom-select is your class name, we are checking for Select Type and finally setting the attribute disabled. We are done. Why its efficient, because looping always cost a lot. We are not using loop here which always has Big 0 impact.
Complete Solution:
Model:
public class EntityTypeModel
{
public string? entityType { get; set; }
}
Controller:
public IActionResult Create()
{
List<SelectListItem> entityTypeList = new List<SelectListItem>();
entityTypeList.Add(new SelectListItem { Text = "Entity-Type-C#", Value = "Entity-Type-C#" });
entityTypeList.Add(new SelectListItem { Text = "Entity-Type-SQL", Value = "Entity-Type-SQL" });
entityTypeList.Add(new SelectListItem { Text = "Entity-Type-Asp.net core", Value = "Entity-Type-Asp.net core" });
ViewBag.entityType = entityTypeList;
return View();
}
View:
#model DotNet6MVCWebApp.Models.EntityTypeModel
#{
ViewData["Title"] = "Create";
}
<h4>Entity Type Dropdown</h4>
<hr />
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label asp-for="entityType" class="control-label"></label>
#Html.DropDownListFor(model => model.entityType, #ViewBag.entityType as SelectList, "Select Type", new { #class = "custom-select"})
<span asp-validation-for="entityType" class="text-danger"></span>
</div>
</div>
</div>
#section scripts {
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<script>
$(document).ready(function () {
$('.custom-select option:contains("Select Type")').attr("disabled", "disabled");
});
</script>
}
Output:
Update:
Another thing you can do is: You can set your "Select Type" text from the backend like this way:
entityTypeList.Add(new SelectListItem { Text = "Select Type", Value = "Select Type" });
and then you can check if the the user has selected Select Type in that case you can update ModelState with the error message as below:
if (EntityTypeModel.entityType.Contains("Select Type"))
{
ModelState.AddModelError("", "Entity Type should not be Select Type");
}

Related

ASP.NET Core view only partially post back the ViewModel

I have a ViewModel that includes 4 different classes with a lot of properties.
Now, if I make a submit in my view, only the properties that are bound to an input field are posted back, which is bad, since I have a table based on one of those classes (which are gone after the submit).
I know I could handle it like this:
#Html.HiddenFor(m => m.class.property)
But with the amount of properties, this seems like a very inconvenient approach.
I could also just get my model via query again, but this also seems like an approach that's not right.
Is there a better approach than those I mentioned above?
Edit:
And I tried it this way too:
#foreach (var property in Model.Mandant.GetType().GetProperties())
{
#Html.HiddenFor(p => property)
}
But for some reasons this doesn't work, sadly.
Edit2 for clarification:
I have an viewModel like this:
public class ValidationViewModel
{
public M_IV_INVOICE Invoice { get; set; }
public List<M_IP_INVOICE_POS> Positions { get;}
public S_KR_KREDITOR_ Kreditor { get; set; }
public S_MD_MANDANTEN Mandant { get; set; }
public ValidationViewModel() { }
public ValidationViewModel(int invoiceId)
{
Invoice = CRUD.GetFirstOrDefault(new M_IV_INVOICE(), string.Format(#"WHERE M_IV_ID IN ({0})", invoiceId));
Positions = Invoice != null ? CRUD.GetList(new M_IP_INVOICE_POS(), string.Format(#"WHERE M_IP_INVOICEID IN ({0})", Invoice.M_IV_ID)) : null;
Kreditor = Invoice?.M_IV_KREDITOR != null ? CRUD.GetFirstOrDefault(new S_KR_KREDITOR_(), string.Format(#"WHERE S_KR_KREDITOR IN ({0})", Invoice.M_IV_KREDITOR), "S_KR_KREDITOR") : null;
Mandant = Invoice?.M_IV_MANDANT != null ? CRUD.GetFirstOrDefault(new S_MD_MANDANTEN(), string.Format(#"WHERE S_MD_FIR IN ({0})", Invoice.M_IV_MANDANT)) : null;
}
}
I have a view which looks like this:
#using (Html.BeginForm("Update", "Home"))
{
#Html.ValidationSummary();
<div class="container">
<div class="row">
<div class="form-group col-2">
#*#Html.LabelFor(m => m.Mandant.S_MD_FIR)
#Html.TextBoxFor(m => m.Mandant.S_MD_FIR, string.Format("{0} - {1}", Model.Mandant?.S_MD_FIR, Model.Mandant.S_MD_BEZEICHNUNG), new { #class = "form-control", placeholder = "0" })
#Html.ValidationMessageFor(m => m.Mandant.S_MD_FIR)*#
#Html.Label("Mandant")
<input readonly value="#string.Format("{0} - {1}", Model.Mandant?.S_MD_FIR, Model.Mandant?.S_MD_BEZEICHNUNG)" class="form-control" placeholder="" id="Mandant" />
</div>
<div class="form-group col-2">
#Html.LabelFor(m => m.Invoice.M_IV_KREDITOR)
#Html.TextBoxFor(m => m.Invoice.M_IV_KREDITOR, new { #class = "form-control", placeholder = "0" })
#Html.ValidationMessageFor(m => m.Invoice.M_IV_KREDITOR)
</div>
<div class="form-group col-2">
#Html.LabelFor(m => m.Invoice.M_IV_INVOICEDATE)
#Html.TextBoxFor(m => m.Invoice.M_IV_INVOICEDATE, new { #class = "form-control", placeholder = "0" })
#Html.ValidationMessageFor(m => m.Invoice.M_IV_INVOICEDATE)
</div>
</div>
.....
<button type="submit" class="btn btn-primary">Update</button>
}
Now, if I press the button and call my update method:
[HttpPost]
public IActionResult Update(ValidationViewModel validationViewModel)
{
if (ModelState.IsValid)
{
validationViewModel.Invoice.Update();
// TODO additional logic
}
return View("Index", validationViewModel);
}
Everything that's not bound to an input field or listed with:
#Html.HiddenFor(m => m.Invoice.M_IV_ID)
is nulled.
And now I'm locking for a more convenient way to circumvent this, if even possible.
ASP.NET does not provide the behavior that you're looking for, as far as I know, there is no #Html.HiddenForModel(model => model.child). I guess it's because if you have that level of data complexity on your view, you might want to simplify it and to present only what's necessary for the view. But you can try to "hack" it with #Html.EditorForModel(), wrapped within an invisible container on your view, something like the snippet below:
<div style="display: none">
#Html.EditorForModel()
#Html.EditorFor(model => model.child1)
#Html.EditorFor(model => model.child2)
#Html.EditorFor(model => model.child3)
</div>
To further elaborate on my problem with the List object:
If I do it the way Dorin Raba showed in the answer:
#Html.EditorFor(model => model.child1)
it won't work because, all the textfields are named without an index, so it's not possible to match the values back.
But I can simply do it this way:
#for (int i = 0; i < Model.M_IP_INVOICE_POS.Count; i++)
{
#Html.EditorFor(model => model.M_IP_INVOICE_POS[i])
}
and now every editor field has the correct name and I get the positions back to the controller.
So no need to query my Positions every time I want to Update something.

Getting the selected value from a DropDownListFor using a ViewBag list

I'm having trouble getting the data from a DropDownListFor using a ViewBag list with my model. Here is my Controller code:
[HttpGet]
public ActionResult JoinTeam()
{
var TeamList = _db.TeamModels.ToList();
SelectList list = new SelectList(TeamList, "Id", "TeamName");
ViewBag.TeamList = list;
return View();
}
And the Razor view form looks like this:
#using (Html.BeginForm("JoinTeam", "Home", FormMethod.Post))
{
#Html.TextBoxFor(m => m.DisplayName, new { #class = "form-control form-control-lg", placeholder = "Enter your Battle Net ID" })
<br/>
#Html.DropDownListFor(m => m.TeamModel, (SelectList)ViewBag.TeamList, "- Select a Team to Join -", new { #class= "form-control form-control-lg" })
<br />
<button type="submit" class="btn btn-primary" style="width:100%;text-align:center;">Submit</button>
}
The TextBoxFor helper is returning the data correctly, but whatever option I have selected in the drop down does not get passed into my post method. Does anyone have any ideas?
The post action does work as it's getting the data from the model for the TextBoxFor help, but here's what it looks like:
[HttpPost]
public async Task<ActionResult> JoinTeam(GuardianModel model)
{
try
{
string BNETId = model.DisplayName.Replace("#", "%23");
long memberId = 0;
if (ModelState.IsValid)
{
Bungie.Responses.SearchPlayersResponse member = await service.SearchPlayers(MembershipType.Blizzard, BNETId);
memberId = member[0].MembershipId;
}
using (var context = new CoCodbEntities1())
{
var g = new GuardianModel
{
MembershipId = memberId.ToString(),
DisplayName = BNETId,
MembershipType = 4,
TeamID = model.TeamModel.Id
};
TempData["UserMessage"] = ViewBag.TeamList.Id;
return RedirectToAction("Success");
}
}
catch
{
}
return View();
}
These are the values getting passed into the Post action
From the screenshot you shared, it looks like TeamModel property is the virtual navigational property of type TeamModel. You should not bother about loading that. All you need to worry about loading the forign key property value (usually a simple type like an int or so.
Your SELECT element name should be TeamID. When the form is submitted, it will map the selected option value to the TeamID property value of your model which is the foreign key property.
#Html.DropDownListFor(m => m.TeamID, (SelectList)ViewBag.TeamList,
"- Select a Team to Join -", new { #class= "form-control form-control-lg" })
While this might fix the issue, It is a good idea to use a view model instead of using your entity class.
I found the issues I was having. All I needed to get passed into the post action was the Id of the TeamModel. So I changed this line:
#Html.DropDownListFor(m => m.TeamModel.Id, (SelectList)ViewBag.TeamList, "- Select a Team to Join -", new { #class= "form-control form-control-lg" })
I just added the Id and it seemed to work.

Setting the default value of an enum dropdown in Razor

I'm trying to create an Item edit screen where the user can set a property of the Item, the ItemType. Ideally, when the user returns to the screen, the dropdown would display the ItemType already associated with the Item.
As it is, regardless of what the item.ItemType is, the dropdown will not reflect that in the dropdown. Is there a way around this?
For reference, my code at the moment is:
<div class="form-group">
#Html.LabelFor(model => model.ItemType, new { #class = "control-label col-xs-4" })
<div class="col-xs-8">
#Html.DropDownListFor(model => model.ItemType, (SelectList)ViewBag.ItemType, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.ItemType, String.Empty, new { #class = "text-danger" })
</div>
</div>
The ViewBag is set with the following:
var ItemType = Enum.GetValues(typeof(ItemType));
ViewBag.ItemType = new SelectList(ItemType);
If you're using ASP.NET MVC 5, try just using the EnumHelper.GetSelectList method. Then you don't need ViewBag.ItemType.
#Html.DropDownListFor(model => model.ItemType, EnumHelper.GetSelectList(typeof(ItemType)), new { #class = "form-control" })
If not, you might need to specify the data value and data text fields of the select list.
var itemTypes = (from ItemType i in Enum.GetValues(typeof(ItemType))
select new SelectListItem { Text = i.ToString(), Value = i.ToString() }).ToList();
ViewBag.ItemType = itemTypes;
Then since it's an IEnumerable<SelectListItem> you'll need to change your cast.
#Html.DropDownListFor(model => model.ItemType, (IEnumerable<SelectListItem>)ViewBag.ItemType, new { #class = "form-control" })
Eventually I found a fix - manual creation of the list.
<select class="form-control valid" data-val="true"
data-val-required="The Item Type field is required." id="ItemType" name="ItemType"
aria-required="true" aria-invalid="false" aria-describedby="ItemType-error">
#foreach(var item in (IEnumerable<SelectListItem>)ViewBag.ItemType)
{
<option value="#item.Value" #(item.Selected ? "selected" : "")>#item.Text</option>
}
</select>
Try to keep as much of the logic outside of the View and in the Controller.
I saw in your self answer that it looks like you have an enum selected from wihin your controller.
I have a DropDownList in one of my apps that contains a list of Enums. It also has a default value selected, but also has specific enums available to the user. The default selection can be set from within the controller.
This example is based on what my needs were, so you'll need to adapt to your case.
In the controller:
public ActionResult Index()
{
ViewBag.NominationStatuses = GetStatusSelectListForProcessView(status)
}
private SelectList GetStatusSelectListForProcessView(string status)
{
var statuses = new List<NominationStatus>(); //NominationStatus is Enum
statuses.Add(NominationStatus.NotQualified);
statuses.Add(NominationStatus.Sanitized);
statuses.Add(NominationStatus.Eligible);
statuses.Add(NominationStatus.Awarded);
var statusesSelectList = statuses
.Select(s => new SelectListItem
{
Value = s.ToString(),
Text = s.ToString()
});
return new SelectList(statusesSelectList, "Value", "Text", status);
}
In the view:
#Html.DropDownList("Status", (SelectList)ViewBag.NominationStatuses)
This approach will automatically set the default item to the enum that was selected in the controller.

C# DropDown List default value

I am using this code to input values from a database table to a dropdown list:
<div class="editor-field">
#Html.DropDownListFor(model => model.TourImageID, new SelectList(Model.Images, "ImageID", "Filename", Model.TourImageID))
</div>
What i am trying to do is add an item to the top of the list, that is not present in the database table.
Something like DROPDOWN LIST VALUES = (DEFAULT-ITEM) + (DATABASE-TABLE-ITEMS)
is that possible? if so, how?
If your Model.Images is of type SelectList, you can do something like this in your controller:
var query = UnitOfWork.GlobalImageLibraryRepository.Images.Select(x => new { x.ImageID, x.Filename });
viewModel.Images = new SelectList(query.AsEnumerable(), "ImageID", "Filename");
viewModel.Images.Insert(0, new SelectListItem { Value = "0", Text = "--Select--" });
I've assumed that you have a method in your GlobalImageLibraryRepository class that returns IQueryable<Images> like this:
public IQueryable<Images> Images { get { return dbcontext.Images; } }
So after all that, your view will look like this:
<div class="editor-field">
#Html.DropDownListFor(model => model.TourImageID, (SelectList)Model.Images, Model.TourImageID))
</div>

DropDownList Binding to ActionResult Create Method MVC 4 VS2012

I'm a brand new user here - but I've been searching for a couple of hours now to solve following problem:
I've got 2 Entities - Category and Item.
Each Item should belong to a Category - therefore I would like to have a DropDownList which shows all existing Categories when Creating a new Item.
So far my code shows the DropDownList with all the Categories, but when I select a Category and Submit the form (POST) the value for Category is always null.
This naturally causes ModelState.IsValid to be false, because Category isn't nullable.
How can I get the User-Selected-Value into my Create(POST) method?
I've got a Controller with following Methods to Create a new Item:
// GET Method
public ActionResult Create()
{
ViewBag.Category = new SelectList(db.CategorySet, "Id", "CategoryName");
return View();
}
[HttpPost]
public ActionResult Create(Item item)
{
if (ModelState.IsValid)
{
db.ItemSet.Add(item);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(item);
}
And this is the DropDownList in my View (Create.cshtml):
<div class="editor-field">
#Html.DropDownList("Category", (IEnumerable<SelectListItem>) ViewBag.Categories, "--Select Category--")
</div>
Finally I ended up with a custom view model - that way I got it working...
For those of you who don't know what a custom view model is:
You create a new class which contains all the values you need to create your new object, in my example a class which contains a SelectList (property) of available Categories, an integer value (property) for SelectedCategoryId and the Item (property) you want to create.
In your cshtml file you add this class as #model ....CustomCreateItemModel and use it in your DropDownList
If your Item has a CategoryId property:
public class Item
{
public int CategoryId {get;set;]
}
You will need to name your DropDownList to "CategoryId" so that the ModelBinder will be able to bind the value correctly
Or use the strongly typed helper:
Html.DropDownListFor(x=>x.CategoryId...)
Thanks Armen.
I had the same issue with my dropdown list being populated OK from the database but the OrganisationID (in my case) not making it to the database when a new record was created (in my case only 0 was always captured) - until I just changed the name of the ViewBag to be identical to the value in the dropdown (i.e. both OrganisationID) - as you had helpfully pointed out - and now it works!
For what it's worth, for anyone else going through the frustration that "Desperate coder" and I went through when our naming wasn't consistent to enable binding, here's what I have used to get a dropdown list working (sorry - NOT using the Entity Framework, but the principle should still be clear and easy to adapt if you are using the EF):
But the key takeaway is identical naming to enable binding. Thanks again Armen!
MODEL
public class Organisation_Names
{
public DataSet GetOrg_Names()
{
SqlConnection cn = new SqlConnection(#"Data Source=XXXXXXXXX;User ID=XXXXXXXXX;Password=XXXXXXXXXXX;Initial Catalog=XXXXXXXXXXXX");
SqlCommand cmd = new SqlCommand("sp_GetOrg_Names", cn);
cn.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
DataSet ds = new DataSet();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(ds);
return ds;
}
}
CONTROLLER
//
// GET: /Services/Create
**public ActionResult Create(Organisation_Names organisation_names)
{
DataSet ds = organisation_names.GetOrg_Names();
ViewBag.OrganisationID = ds.Tables[0];
List<SelectListItem> items = new List<SelectListItem>();
foreach (System.Data.DataRow dr in ViewBag.OrganisationID.Rows)
{
items.Add(new SelectListItem { Text = #dr["OrganisationName"].ToString(), Value = #dr["OrganisationID"].ToString() });
}
ViewBag.OrganisationID = items;
return View();
}
//
// POST: /Services/Create
[HttpPost]
[ValidateAntiForgeryToken]
**public ActionResult Create(CreateServiceModel createservicemodel, Organisation_Names organisation_names, FormCollection selection)
{
DataSet ds = organisation_names.GetOrg_Names();
if (ds == null)
{
return HttpNotFound();
}
ViewBag.OrganisationID = ds.Tables[0];
List<SelectListItem> items = new List<SelectListItem>();
foreach (System.Data.DataRow dr in ViewBag.OrganisationID.Rows)
{
items.Add(new SelectListItem { Text = #dr["OrganisationName"].ToString(), Value = #dr["OrganisationID"] + 1.ToString() });
}
ViewBag.OrganisationID = items;**
if (this.IsCaptchaVerify("Answer was incorrect. Please try again."))
{
try
{
int _records = createservicemodel.CreateService(createservicemodel.OrganisationID, createservicemodel.ServiceName, createservicemodel.ServiceDescription, createservicemodel.ServiceComments, createservicemodel.ServiceIdentificationNumber, createservicemodel.CreatedBy, createservicemodel.NewServiceID);
if (_records > 0)
{
return RedirectToAction("Index", "Services");
}
}
catch
//else
{
ModelState.AddModelError("", "Cannot Create");
}
}
{
return View(createservicemodel);
}
}
VIEW
#model WS_TKC_MVC4.Models.CreateServiceModel
#using CaptchaMvc.HtmlHelpers
#using WS_TKC_MVC4.Models
#{ViewBag.Title = "Service added by " ;} #User.Identity.Name
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"> </script>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>CreateServiceModel</legend>
<div class="editor-label">
<p>Select Organisation</p>
</div>
<div class="editor-field">
#Html.DropDownList("OrganisationID")
#Html.ValidationMessageFor(model => model.OrganisationID)
#Html.EditorFor(model => model.OrganisationID)
</div>
(Some more fields)
<div class="editor-label">
#Html.LabelFor(model => model.MathCaptcha)
</div>
#Html.MathCaptcha("Refresh", "Type answer below", "Answer is a required field.")
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>

Categories

Resources