Blazor/Razor: InputSelect with Enum? - razor

How can I use the values of an enum class as options for an InputSelect?
Example enum:
public enum Test
{
Test1,
Test2
}
I am using with Blazor with Razor components.

Here's a working sample how to use enum in InputSelect component:
<EditForm EditContext="#EditContext">
<DataAnnotationsValidator />
<div class="form-group">
<label for="name">Enter your Name: </label>
<InputText Id="name" Class="form-control" #bind-Value="#comment.Name"></InputText>
<ValidationMessage For="#(() => comment.Name)" />
</div>
<div class="form-group">
<label for="body">Select your country: </label>
<InputSelect #bind-Value="#comment.Country" >
#foreach (var country in Enum.GetValues(typeof(Country)))
{
<option value="#country">#country</option>
}
</InputSelect>
<ValidationMessage For="#(() => comment.Country)" />
</div>
<p>
<button type="submit">Submit</button>
</p>
</EditForm>
#code
{
private EditContext EditContext;
private Comment comment = new Comment();
protected override void OnInitialized()
{
EditContext = new EditContext(comment);
base.OnInitialized();
}
public enum Country
{
USA = 1,
Britain,
Germany,
Israel
}
public class Comment
{
public string Name { get; set; }
public Country Country { get; set; }
}
}
Hope this helps...

So in short it's like this:
<InputSelect #bind-Value="#YourEnum">
#foreach (var value in Enum.GetValues<YourEnumType>()) {
<option value="#value">#value</option>
}
</InputSelect>

#enet answer is correct.
To add to this, sometimes enum values won't accept specific chars. you can edit the display of enum value to display specific chars in the code if you have filtered or changed enum values to store correctly. like below in my enum i replace all spaces with underscore. so you can add this to the code to display the enum values on the dropdown correctly.
<InputSelect #bind-Value="#updateUserDetails.Nationality" class="dropDownSelectList">
#foreach (var countryName in Enum.GetValues(typeof(Nationality)))
{
<option value="#countryName">#(#countryName.ToString().Replace("_", " ").Replace("HH", "-"))</option>
}
</InputSelect>

<select>
#foreach (var Item in Enum.GetValues(typeof( DayOfWeek)))
{
<option value="#Item">#Item</option>
}

Related

MultiSelectList displaying only one selected value out of Selectedvalues

For httppost method MultiSelectList shows only one value in view side.
My view
<div class="col-md-6 form-group">
<select class="form-control selectpicker" required="" asp-for="DomID" asp-items=" ViewBag.DomList as MultiSelectList" multiple data-live-search="true"
placeholder="Select Categories"
onchange="console.log($(this).children(':selected').length)">
</select>
</div>
MY Controller
[HttpPost]
public IActionResult controllerAction([Bind]LogModel logmodel)
{
logmodel.selectedvals= // Has Submitted/selected values
List<LogModel> domList = new List<LogModel>();
domList = ;//getting values for dropdown
ViewBag.DomList = new MultiSelectList(domList , "DomID", "Dom", logmodel.selectedvals);
return view(logmodel);
}
My dropdown shows only one value selected from out of all selected values i.e.. from
logmodel.selectedvals in post action.
If I set hardcode selected values in httpget method for multiselectlist then it's shows
selected values properly. What I'm doing wrong here?
Updated
Log Model
public Int64 DomID { get; set; }
public string Dom { get; set; }
public List<Int64> selectedvals { get; set; }
Try to remove logmodel from return view(logmodel);
Below is a work demo, you can refer to it , hope it can help.
In Controller:
public IActionResult SetList()
{
return View();
}
[HttpPost]
public IActionResult ShowMList(LogModel logmodel)
{
List<LogModel> domList = new List<LogModel>();
domList.Add(new LogModel() { DomID = 1, Dom = "AA" });
domList.Add(new LogModel() { DomID = 2, Dom = "BB" });
domList.Add(new LogModel() { DomID = 3, Dom = "CC" });
ViewBag.DomList = new MultiSelectList(domList, "DomID", "Dom", logmodel.selectedvals);
return View();
}
SetList.cshtml:
#model LogModel
<form asp-action="ShowMList">
<select name="selectedvals" class="form-control" multiple>
<option value="1">AA</option>
<option value="2">BB</option>
<option value="3">CC</option>
</select>
<input type="submit" value="submit" />
</form>
ShowMList.cshtml:
#model LogModel
<div class="col-md-6 form-group">
<select class="form-control selectpicker" required="" asp-for="DomID" asp-items=" ViewBag.DomList as MultiSelectList" multiple data-live-search="true"
placeholder="Select Categories"
onchange="console.log($(this).children(':selected').length)">
</select>
</div>
result:
In aspfor int was using int instead of <int>

Input type number strange behaviour

I'm building a fruit and vegetables e-commerce app. I have made a system for users to add items to cart by entering values in an <input type="number"> field, within a form.
The problem I'm having is that when I enter "1.2" for example, my server receives the value "12". But when I enter the value "1", my server just receives the value "1". This really bugs me. Does anyone know why this happens?
Thanks in advance.
Some data for context: my backend is build in Asp.Net Core 3.x. The backend endpoint looks like this:
[HttpPost]
public ActionResult UpdateShoppingCart(int productId, float amount)
{
Console.WriteLine(amount);
var selectedProduct = _productRepository.Products.SingleOrDefault(p => p.Id == productId);
float productCount = 0;
if(selectedProduct != null)
{
productCount = _shoppingCart.UpdateCart(selectedProduct, realAmount);
}
return Redirect(Request.Headers["Referer"].ToString());
}
The html part looks like this
<div class="text-center">
<div class="float-left">
<p>Cantidad:</p>
</div>
<div class="float-right">
<form method="post" class="form-inline" asp-controller="ShoppingCart" asp-action="UpdateShoppingCart">
<input type="hidden" name="productId" value="#Model.Product.Id"/>
<input name="amount" type="number" class="form-control h-auto input-add-to-cart" data-id="#Model.Product.Id" min=0 step="0.1" value="#(Model.ShoppingCartItem != null ? (Model.ShoppingCartItem.Amount).ToString(new CultureInfo("en-US")) : (0).ToString())"/>
<button type="submit" id="update-button-#Model.Product.Id" disabled class="ml-1 btn btn-sm btn-outline-warning"><i class="material-icons material-icons-actual-font" disabled>shopping_cart</i>Actualizar</button>
</form>
</div>
</div>
UPDATE:
The code for the ShoppingCartItem model is the following:
public class ShoppingCartItem
{
public int Id { get; set; }
public Product Product { get; set; }
public int ProductId { get; set; }
public float Amount { get; set; }
public string ShoppingCartId { get; set; }
}
SECOND UPDATE:
Could it be that i'm setting a culture in the thread that uses the comma as a dot?
In the Configure method of Startup, i'm setting
var cultureInfo = new CultureInfo("es-CL");
cultureInfo.NumberFormat.CurrencySymbol = "$";
CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
Ok, that was it.
The problem was that my Browser was setting the decimal separator as a dot (for example, 4.7) and my backend was expecting a comma (for example, 4,7) so that confused my application.
The culprit was what was posted on my second update, that was
var cultureInfo = new CultureInfo("es-CL");
CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;

Value default with thymleaf in a combobox

I have a problem with thymleaf. I have a form with a combobox and some fields. I want put default value in the combobox and the clausure "selected" not working for me.
The code is this:
<select class="dsp-inline form-control" th:field="*{tipoDocumento}" required="required" th:disabled="${permisoXestion == false}">
<option value="" th:text="#{select.option.default}"> </option>
<option th:each="row : ${tipoDocumento}" th:value="${row}" th:text="#{${row.value}}" th:selected="#{${row==2}}"></option>
</select>
Where "tipoDocumento" is a enum with two values:
public enum TipoDocumento {
PUBLICO("documento.tipo.publico"),
PRIVADO("documento.tipo.privado");
private String property;
private String value;
private TipoDocumento(String property) {
this(property, null);
}
private TipoDocumento(String value, String property) {
this.value = value;
this.property = property;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
}
Can someone help me?
The selected tag should work. Remember it need to be added like selected="selected". I have used it on several selects and it always work. Also, in your th:each you need to remove the th:selected="#{${row==2}}" element, otherwise your first option won't be the default one.
<select class="dsp-inline form-control" required="required" th:disabled="${permisoXestion == false}">
<option value="" th:text="#{select.option.default}"></option>
<option th:each="row, iter : ${tipoDocumento}" th:value="${row}" th:text="#{${row.value}}" th:selected="${iter.count eq 2} ? 'selected' : 'false'"></option>
</select>
if you use the th:selected you cannot not use the th:field. You have to replace it with a name attribute.
So, can you replace
<select class="dsp-inline form-control" th:field="*{tipoDocumento}" required="required" th:disabled="${permisoXestion == false}">
with
<select class="dsp-inline form-control" name="tipoDocumento" required="required" th:disabled="${permisoXestion == false}">
Also, the condition of the th:selected
can you replace
th:selected="#{${row==2}}"
with
th:selected="${row==2}"

Edit view not being populated with objects data

I am quite new to ASP .Net, and could use some help... I have an ASP .Net Core 1.1 web app. In it, I have an "Edit" view for editing a simple object, which a corresponding controller calls when routed to it. This is the view:
#model InspectionsTestClient.Models.Property
#{
ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
#Html.ValidationSummary();
<form asp-action="Edit">
<div class="form-horizontal">
<h4>Property</h4>
<hr />
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="UnitNumber" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="UnitNumber" class="form-control" />
<span asp-validation-for="UnitNumber" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="BuildingName" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="BuildingName" class="form-control" />
<span asp-validation-for="BuildingName" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Street" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Street" class="form-control" />
<span asp-validation-for="Street" class="text-danger"></span>
</div>
</div>
</div>
</form>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
This is the controller which calls that view:
// GET: Property/Edit/5
public ActionResult Edit(int id)
{
return View();
}
And this is the model:
namespace InspectionsTestClient.Models
{
//[Table("property")]
public class Property
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int? Id { get; set; }
[MaxLength(10, ErrorMessage = "Unit number too long")]
[Display(Name = "Unit #")]
public string UnitNumber { get; set; }
[MaxLength(45, ErrorMessage = "BuildingName name too long")]
public string BuildingName { get; set; }
[MaxLength(45, ErrorMessage = "Street too long")]
public string Street { get; set; }
}
}
So when I navigate to that page, the controller fires up, and returns the Edit view. I have confirmed the parameter "id" is populated. When the Edit view loads in the browser, however, all the input textboxes are empty. I would expect them to be pre-populated with the values for the object in question. What am I missing?
The issue you are experiencing is happening because you are not returning that object to the view.. actually in your case you're not even going out to the db to get the object.
You need to edit you Edit action to something like this:
// GET: Property/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var object = db.TableName.Find(id);
// db = connectionstring
// TableName = database table that holds the object that you want to return
if (object == null)
{
return HttpNotFound();
}
return View(object);
}
Let me know if this helps
public class PropertyController
{
private readonly ApplicationDbContext _dbContext;
public PropertyController(ApplicationDbContext dbContext){
_dbContext = dbContext;
}
//GET: Property/Edit/5
public async Task<IActionResult> Edit(int id)
{
var property = await _dbContext.Property.FirstOrDefaultAsync(p => p.Id == id);
return View(property);
}
}
If you don't pull the data from the database and send it to the view of course it will always be blank. Edit(int id) there will be 2, both slightly different from the other.
[HttpPost]
[ValidateAntiForgeryToken]
//Post: Property/Edit/5
public async Task<IActionResult> Edit(int id, [Bind("Id", "UnitNumber", "BuildingNumber", "Street")] Property property)
{
if(ModelState.IsValid){
}
else{
}
}
not everyting is present but that is part of your adventure.

ASP.NET MVC Model list binding

Here is my model:
public class Items
{
public string Foo { get; set; }
public string Bar { get; set; }
}
Controller:
public ActionResult Index()
{
var model = new List<Items>
{
new Items
{
Foo = "foo",
Bar = "bar"
},
new Items
{
Foo = "ai",
Bar = "ia"
},
new Items
{
Foo = "one",
Bar = "two"
}
};
return View(model);
}
[HttpPost]
public ActionResult Index(List<Items> model)
{
return View(model);
}
View (Index):
#using (Html.BeginForm())
{
for (int i = 0; i < Model.Count; i++)
{
<div onclick="$(this).remove();">
#Html.TextBoxFor(model => model[i].Foo) <br/>
#Html.TextBoxFor(model => model[i].Bar)
</div>
}
<div>
<input type="submit"/>
</div>
}
I delete second pair:
<div onclick="$(this).remove();">
<input name="[0].Foo" type="text" value="foo"> <br>
<input name="[0].Bar" type="text" value="bar">
</div>
<div onclick="$(this).remove();">
<input name="[2].Foo" type="text" value="one"> <br>
<input name="[2].Bar" type="text" value="two">
</div>
When posting, i get only first pair ("foo" and "bar"). It's because third pair has index "2". I want to get both pairs(Not using FormCollection. I want it to bind automatically). In reality, I have many other inputs on form, so i don't want to reload and reattach indices to each input. Can you help me?
This may be helpful to you....
need to place Hidden field on each item...
MVC3 Non-Sequential Indices and DefaultModelBinder
I found solution, thanks to Amit Prajapati:
#using (Html.BeginForm())
{
for (int i = 0; i < Model.Count; i++)
{
var identifier = Guid.NewGuid();
<div onclick="$(this).remove();">
#Html.Hidden("Index", identifier)
#Html.TextBox("[" + identifier + "].Foo")
<br/>
#Html.TextBox("[" + identifier + "].Bar")
</div>
}
<div>
<input type="submit" />
</div>
}