Custom Blazor Select Option - not selecting initial item from bound value - html-select

While creating custom components I wanted to extend the Select with a custom Option component, so that I can add extra parameters etc.
A simplified version of this:
<option value="#value">#ChildContent</option>
#code {
[Parameter] public RenderFragment ChildContent { get; set; }
[Parameter] public string value { get; set; }
}
I'm using the component in the exactly the same way as the option tag, and html-wise, the code renders exactly the same.
It all appears to work fine, but doesn't do an initial bind eg. the top option is always selected, but only visibly - the Value is empty string.

You just need to create custom razor component -> CustomOption.razor with such content
<option value="#value" class="#specAttribute">#ChildContent</option>
#code {
[Parameter] public RenderFragment ChildContent { get; set; }
[Parameter] public string value { get; set; }
[Parameter] public string specAttribute { get; set; }
}
And then use it:
<InputSelect #bind-Value="#language">
<CustomOption value="English" specAttribute="list-item">English</CustomOption>
<CustomOption value="Spanish" specAttribute="list-item">Spanish</CustomOption>
</InputSelect>

After further investigation this has been identified as a bug.
Links to two issues on GitHub dotnet/aspnetcore:
elements inserted dynamically during same diff as don't get auto-selected #21453
Blazor: Dynamic not setting selected value #21432

Related

How to set default value in DropDownListFor in a loop?

I just want to show a drop down list on my view with a selected value/state, but the problem is that selected state/value doesn't work. After some researching on this website I couldn't find my solution and write this post, It seems it's simple but I'm confused. Maybe my case is a little complicated.
In my cause my drop down gets items(MarriageList) froma listand selected values from another list(PersonList).
Main model on my view, I create an instant and pass it to view by controller:
Public class MyPageModel
{
//this is my marriage list and to use anywhere on my codes
Public List<Sub_MarriageModel> MarriageList { get; set; }
//this is person list selected marriage is in this list
Public List<Person> PersonList{get;set;}
}
This is my items class:
public class Sub_MarriageModel
{
public int ID{ get; set; } // 0,1,2
public string Name { get; set; } //single,married
}
public class Person
{
public int SelectesState{ get; set; } // 0,1,2
}
View is:
#for (int i=0;i<Model.MarriageList.Count;i++)
{
#Html.DropDownListFor(m=>m.PersonList[i].SelectesState,
new SelectList(Model.MarriagesList, "ID", "Name"))
}
HTML result:
<select id="PersonList_0__SelectesState" name="PersonList[0].SelectesState">
<option value="0">Single</option>
<option value="1">Married</option>
<option value="2">Unknow</option>
</select>
why are you MarriageList do you need multiple dropdowns
#Html.DropDownListFor(m=>m.PersonList[i].SelectesState,new SelectList(Model.MarriagesList, "ID", "Name"), "Unknow")

MVC pattern and flexibility?

I'm fairly new to the MVC pattern and as I go deeper in developping using this logic, I'm facing some issues which I can overcome, but I am not sure if I'm doing it the proper way (best practice).
So the issue:
I have a View that receives a Model that has the following structure:
public class MyViewModel
{
public string Title { get; set; }
public string Subtitle { get; set; }
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
public List<MyItem> ListOne { get; set; }
public List<MyItem> ListTwo { get; set; }
public List<MyItem> ListThree { get; set; }
public List<MyItem> ListFour { get; set; }
public List<MyItem> ListFive { get; set; }
}
I want the View to show the first item from each List only when the list has records in it. So what I am trying to do on the View right now is something like this:
<div>
#if(Model.ListOne != null)
{
<img src="#Html.DisplayFor(model => Model.ListOne.First().Filename)" style="max-height: 800px;max-width:800px; padding-bottom: 5px;" />
}
</div>
but when I run the code, I get an error stating System.InvalidOperationException: Sequence contains no elements. So this means, as I understand it, that the View is first fully rendered and after that the code within is parsed and converted to the final HTML output (is this how it works? could use some clarification here also)
So, what is the best way to accomplish this? Do you loose flexibility when using MVC? Right now, it feels like it. This would be so much easier to accomplish when you had your code "mixed" with the HTML. Don't get me wrong, it is very clear to me the advantadges that using design patterns bring to a developer, but for this particular problem, it is really making me wonder about how flexible it actually is.
Razor is rendering this in a single pass from the point of view of your model, and you can freely mix code with HTML - that's what makes it so awesome!
The problem here seems to be the way you are trying to access the list.
Try changing this:
#if(Model.ListOne != null)
to this:
#if(Model.ListOne.Any())
At the moment you are only checking that Model.ListOne isn't null - i.e hasn't been initialised at some point in your model via ListOne=new List<MyItem>() or something similar - but what you really need to check is if Model.ListOne is empty or not.
I'd say that you should try to make sure as far as possible that you don't have null model properties when writing your view, it makes it very messy to have to mix in null checks; better to ensure that any model property you want to access in your view is intialised before you give the model to the view.

Navigation Properties on Post Action

I need to access navigation properties on a post edit action but the current way I did that looks not the best alternative as I make a call to database and "reupdate" the model. Is there a better solution?
public class Foo
{
public int Id { get; set; }
public string SomeProp { get; set; }
}
public class Bar
{
public int Id { get; set; }
public int FooId { get; set; }
public Foo Foo { get; set; }
}
[HttpPost]
public ActionResult Edit(Bar bar)
{
// Here bar.FooId is set but bar.Foo is null as bar is not a Dynamic Proxy.
...
bar = db.Bar.Find(bar.id);
TryUpdateModel(bar);
return View(bar); // Here bar.Foo is set.
}
Another way I found is:
db.Bar.Attach(bar);
db.Entity<Bar>(bar).Reference(b => b.Foo).Load();
But it requires I make a reference to all navigation properties I need.
I am not 100% sure if this is the correct or best way of doing it but, in your UI form that is handling the post either the UI elements need to be bound to the navigation properties or you could also pass them along as hidden fields if they are not being modified
<!-- example of hidden properties -->
#Html.HiddenFor(x=>x.Foo.FooId)
<!-- exampld of editable UI element mapped to navigation property's someprop property -->
#Html.TextBoxFor(x=>x.Foo.SomeProp)

asp.net mvc model binding fails for <List> items in editor template

I've searched many posts on SO and still not sure what I did wrong here. I have a model for "Order" which includes a <list> of "OrderItem"
public class Order
{
public int OrderId { get; set; }
public int CustId { get; set; }
public DateTime OrderDate { get; set; }
public int OrderType { get; set; }
...
...
public List<OrderItem> OrderItems = new List<OrderItem>();
}
public class OrderItem
{
public string ProductCode { get; set; }
public decimal RetailPrice { get; set; }
public string ProductQuantity { get; set; }
}
In my view, which is strongly typed to the Order model, I am using an Editor Template to display the order items
#model FTG.Models.Order
#Html.EditorFor(x => x.OrderItems)
and the editor template seems to assign a proper name for the model binding to occur:
input type="number" id="OrderItems_0__ProductQuantity" name="OrderItems[0].ProductQuantity"...
input type="number" id="OrderItems_1__ProductQuantity" name="OrderItems[1].ProductQuantity"...
But my model comes back to the controller with count=0 for the list. The rest of the model looks fine, I just can't get the values from the list of orderitems.
Does anyone know what I am doing wrong, or what I am missing?
I think your model class is missing a property for the child list. Try adding a property for the OrderItems list.
OrderItems is a field, not a property. You need to make it a property with a getter and setter, then in your constructor you create the empty list and assign it to the property.

Model attributes to ignore validation of html entities

I want to input html in the database and also display it back as html. I wrote my view model like this:
public class TemplateVM
{
[HiddenInput(DisplayValue = false)]
public int TemplateId { get; set; }
public string Name { get; set; }
public string Content { get; set; }
}
the property Content should be able to accept html. How can I do this? Right now, it throws the error of:
A potentially dangerous Request.Form value was detected from the client (Content="<p>test</p>").
I'm aware of using this on the action, but I dont want it to apply to every property.:
[ValidateInput(false)]
Instead of using ValidateInput attribute on entire model, I suggest you use AllowHtml attribute on Content property:
public class TemplateVM
{
[HiddenInput(DisplayValue = false)]
public int TemplateId { get; set; }
public string Name { get; set; }
[AllowHtml]
public string Content { get; set; }
}
This attribute is only applied for Content property, while other properties are still validated.
Put [ValidateInput(false)] on top of TemplateVM. It will apply to all properties.

Resources