P11SelectMultiple Component
P11SelectMultiple component provides a multi-selection dropdown list, wrapping the native HTML <select multiple> element. It enables users to select multiple options from a predefined list, integrated with Bootstrap's .form-select class for consistent styling and offering flexible data binding and accessibility features.P11Select, options can be populated via an Items collection with expressions/fields, or manually through ChildContent. Ensure your binding target (@bind-Value) for this component is an ICollection<TValue> (e.g., List<string> or HashSet<int>) to correctly handle multiple selections.P11SelectMultiple Component Examples
These examples demonstrate various configurations and functionalities of the P11SelectMultiple component, showcasing its flexibility for different use cases.
1. Standard Usage with List of Objects (Multiple Selection)
Selecting multiple names from a list of Person objects.
Selected Person IDs: Nothing selected
Implementation
<h4 class="mb-3">1. Standard Usage with List of Objects (Multiple Selection)</h4>
<p>Selecting multiple names from a list of <code>Person</code> objects.</p>
<div class="mb-4">
<label for="multiPersonSelect" class="form-label">Select Persons (Multiple Selection):</label>
<P11SelectMultiple TItem="Person" TValue="int"
Id="multiPersonSelect"
@bind-Value="selectedPersonIds"
Items="people2"
ItemValueExpression="p => p.Id"
ItemTextExpression="p => p.Name"
PlaceholderText="-- No selection --"
OnChanged="OnMultiplePersonsChanged"
CssClass="form-select-lg"
AriaLabel="Select multiple persons dropdown">
</P11SelectMultiple>
<p class="mt-2">
Selected Person IDs:
<strong>
@(selectedPersonIds != null && selectedPersonIds.Any()
? string.Join(", ", selectedPersonIds)
: "Nothing selected")
</strong>
</p>
@if (!string.IsNullOrEmpty(multiPersonChangedMessage))
{
<p class="text-info">@multiPersonChangedMessage</p>
}
</div>@code {
// Person Model (often in a separate .cs file, e.g., Models/Person.cs)
public class Person
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string City { get; set; } = string.Empty;
}
// Data for examples
private List<Person> people2 = new List<Person>
{
new Person { Id = 1, Name = "Alice", City = "New York" },
new Person { Id = 2, Name = "Bob", City = "London" },
new Person { Id = 3, Name = "Charlie", City = "Paris" },
new Person { Id = 4, Name = "Diana", City = "Berlin" }
};
// Properties for binding P11SelectMultiple
private ICollection<int> selectedPersonIds = new List<int>(); // List<int> for multiple selection
private string? multiPersonChangedMessage;
// Event handlers for P11SelectMultiple
private void OnMultiplePersonsChanged(ICollection<int> newPersonIds)
{
multiPersonChangedMessage = $"Personen geändert zu: {string.Join(", ", newPersonIds ?? new List<int>())}";
Console.WriteLine(multiPersonChangedMessage);
}
}2. Usage with Enum (Multiple Selection)
Selecting multiple priorities from an enum.
Selected Priorities: Nothing selected
Implementation
<h4 class="mb-3">2. Usage with Enum (Multiple Selection)</h4>
<p>Selecting multiple priorities from an <code>enum</code>.</p>
<div class="mb-4">
<label for="multiPrioritySelect" class="form-label">Select Priorities (Multiple Selection):</label>
<P11SelectMultiple TItem="Priority" TValue="Priority"
Id="multiPrioritySelect"
@bind-Value="selectedPriorities"
Items="Enum.GetValues<Priority>()"
ItemValueExpression="p => p"
ItemTextExpression="p => p.ToString()"
PlaceholderText="-- Select Priorities --"
AriaLabel="Select multiple priorities dropdown">
</P11SelectMultiple>
<p class="mt-2">
Selected Priorities:
<strong>
@(selectedPriorities != null && selectedPriorities.Any()
? string.Join(", ", selectedPriorities)
: "Nothing selected")
</strong>
</p>
</div>@code {
// Enum definition (if not already globally defined)
public enum Priority
{
Low,
Medium,
High,
Critical
}
// Properties for binding P11SelectMultiple
private ICollection<Priority> selectedPriorities = new List<Priority>(); // List<Priority> for multiple enum selection
}3. Manual Options (ChildContent) (Multiple Selection)
Direct rendering of <option> tags within the component for multiple selection.
Selected Cities: MUN
Implementation
<h4 class="mb-3">3. Manual Options (ChildContent) (Multiple Selection)</h4>
<p>Direct rendering of <code><option></code> tags within the component for multiple selection.</p>
<div class="mb-4">
<label for="multiCitySelect" class="form-label">Select Cities Manually (Multiple Selection):</label>
<P11SelectMultiple TItem="string" TValue="string"
Id="multiCitySelect"
@bind-Value="selectedCities"
PlaceholderText="Select cities manually"
AriaLabel="Select multiple cities dropdown">
<option value="BER">Berlin</option>
<option value="MUN">Munich</option>
<option value="HAM">Hamburg</option>
<option value="COL">Cologne</option>
<option value="FRA">Frankfurt</option>
</P11SelectMultiple>
<p class="mt-2">
Selected Cities:
<strong>
@(selectedCities != null && selectedCities.Any()
? string.Join(", ", selectedCities)
: "Nothing selected")
</strong>
</p>
</div>@code {
private ICollection<string> selectedCities = new List<string> { "MUN" }; // Pre-selected for manual example
}4. Disabled Select (Multiple Selection)
A multi-selection field that is not interactive.
Disabled Selection: 1, 3
Implementation
<h4 class="mb-3">4. Disabled Select (Multiple Selection)</h4>
<p>A multi-selection field that is not interactive.</p>
<div class="mb-4">
<label for="disabledMultiSelect" class="form-label">Disabled Multiple Selection:</label>
<P11SelectMultiple TItem="Person" TValue="int"
Id="disabledMultiSelect"
@bind-Value="disabledSelectedPersonIds"
Items="people2"
ItemValueExpression="p => p.Id"
ItemTextExpression="p => p.Name"
IsDisabled="true"
PlaceholderText="Selection disabled"
AriaLabel="Disabled multiple selection dropdown">
</P11SelectMultiple>
<p class="mt-2">
Disabled Selection:
<strong>
@(disabledSelectedPersonIds != null && disabledSelectedPersonIds.Any()
? string.Join(", ", disabledSelectedPersonIds)
: "Nothing selected")
</strong>
</p>
</div>@code {
// Person Model (often in a separate .cs file, e.g., Models/Person.cs)
public class Person
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string City { get; set; } = string.Empty;
}
// Data for examples
private List<Person> people2 = new List<Person>
{
new Person { Id = 1, Name = "Alice", City = "New York" },
new Person { Id = 2, Name = "Bob", City = "London" },
new Person { Id = 3, Name = "Charlie", City = "Paris" },
new Person { Id = 4, Name = "Diana", City = "Berlin" }
};
// Properties for binding P11SelectMultiple
private ICollection<int> disabledSelectedPersonIds = new List<int> { 1, 3 }; // Pre-selected for disabled example
}5. Validation in EditForm (Multiple Selection)
Demonstrates integration with Blazor's EditForm and validation mechanisms for multiple selection.
AOT warning: An example of manual options with short as TValue.
Since short is not explicitly handled in the component's parsing logic,
it falls back to Convert.ChangeType, which should trigger an AOT/Trimming warning
in the user interface.
Selected short numbers: Nothing selected
Implementation
<h4 class="mb-3">5. Validation in EditForm (Multiple Selection)</h4>
<p>Demonstrates integration with Blazor's <code>EditForm</code> and validation mechanisms for multiple selection.</p>
<div class="mb-4">
<EditForm Model="validationModelMultiple" OnValidSubmit="HandleValidSubmit3" OnInvalidSubmit="HandleInvalidSubmit3">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="mb-3">
<label for="requiredMultiPersonSelect" class="form-label">Required Field Persons (Multiple Selection):</label>
<P11SelectMultiple TItem="Person" TValue="int"
Id="requiredMultiPersonSelect"
@bind-Value="validationModelMultiple.SelectedRequiredPersonIds"
Items="people2"
ItemValueExpression="p => p.Id"
ItemTextExpression="p => p.Name"
PlaceholderText="-- Please select --"
AriaLabel="Required Persons Dropdown">
</P11SelectMultiple>
<ValidationMessage For="@(() => validationModelMultiple.SelectedRequiredPersonIds)" />
</div>
<div class="mb-3">
<label for="requiredMultiPrioritySelect" class="form-label">Required Field Priorities (Multiple Selection):</label>
<P11SelectMultiple TItem="Priority" TValue="Priority"
Id="requiredMultiPrioritySelect"
@bind-Value="validationModelMultiple.SelectedRequiredPriorities"
Items="Enum.GetValues<Priority>()"
ItemValueExpression="p => p"
ItemTextExpression="p => p.ToString()"
PlaceholderText="-- Please select --"
AriaLabel="Required Priorities Dropdown">
</P11SelectMultiple>
<ValidationMessage For="@(() => validationModelMultiple.SelectedRequiredPriorities)" />
</div>
<button type="submit" class="btn btn-primary">Submit Form</button>
<p class="mt-2">Validation Status: <strong>@validationStatus3</strong></p>
</EditForm>
</div>
<br />
<br />
<p>
AOT warning: An example of manual options with <code>short</code> as <code>TValue</code>.
Since <code>short</code> is not explicitly handled in the component's parsing logic,
it falls back to <code>Convert.ChangeType</code>, which should trigger an AOT/Trimming warning
in the user interface.
</p>
<div class="mb-4">
<label for="multiShortNumberSelect" class="form-label">Manually select short numbers:</label>
<P11SelectMultiple TItem="short" TValue="short"
Id="multiShortNumberSelect"
@bind-Value="selectedShortNumbers"
PlaceholderText="Manually select short numbers"
AriaLabel="Dropdown for multiple selection of short numbers"
SkipValidation=false>
<option value="10">Ten</option>
<option value="20">Twenty</option>
<option value="30">Thirty</option>
<option value="40">Forty</option>
<option value="50">Fifty</option>
</P11SelectMultiple>
<p class="mt-2">
Selected short numbers:
<strong>
@(selectedShortNumbers != null && selectedShortNumbers.Any()
? string.Join(", ", selectedShortNumbers)
: "Nothing selected")
</strong>
</p>
</div>@* You may need the using *@
@* @using System.ComponentModel.DataAnnotations *@
@code {
// Person Model (often in a separate .cs file, e.g., Models/Person.cs)
public class Person
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string City { get; set; } = string.Empty;
}
// Data for examples
private List<Person> people2 = new List<Person>
{
new Person { Id = 1, Name = "Alice", City = "New York" },
new Person { Id = 2, Name = "Bob", City = "London" },
new Person { Id = 3, Name = "Charlie", City = "Paris" },
new Person { Id = 4, Name = "Diana", City = "Berlin" }
};
// Enum definition (if not already globally defined)
public enum Priority
{
Low,
Medium,
High,
Critical
}
// Validation Model for Multiple Select (often in a separate .cs file)
public class ValidationTestModelMultiple
{
[Required(ErrorMessage = "Bitte wählen Sie mindestens eine Person aus.")]
// For collections, Required checks if the collection is null.
// To check if it's empty, you might need a custom validation attribute or check in OnValidSubmit.
// However, a simple Required will catch a null collection.
public ICollection<int>? SelectedRequiredPersonIds { get; set; } = new List<int>();
[Required(ErrorMessage = "Bitte wählen Sie mindestens eine Priorität aus.")]
public ICollection<Priority>? SelectedRequiredPriorities { get; set; } = new List<Priority>();
}
// Model for validation example
private ValidationTestModelMultiple validationModelMultiple = new ValidationTestModelMultiple();
private string validationStatus3 = "Warten auf Absenden...";
private ICollection<short> selectedShortNumbers { get; set; } = new List<short>();
private void HandleValidSubmit3()
{
validationStatus3 = "Formular ist GÜLTIG!";
Console.WriteLine($"Validierung erfolgreich. Personen: {string.Join(", ", validationModelMultiple.SelectedRequiredPersonIds ?? new List<int>())}, Prioritäten: {string.Join(", ", validationModelMultiple.SelectedRequiredPriorities ?? new List<Priority>())}");
}
private void HandleInvalidSubmit3()
{
validationStatus3 = "Formular ist UNGÜLTIG!";
Console.WriteLine("Validierung fehlgeschlagen.");
}
}6. OnChanged Event Example
This example demonstrates how to use the OnChanged event to react to changes in the selected values. The current selections are displayed immediately after a change.
Selected Languages (via OnChanged): None
Implementation
<h4 class="mb-3">6. OnChanged Event Example</h4>
<p>This example demonstrates how to use the <code>OnChanged</code> event to react to changes in the selected values. The current selections are displayed immediately after a change.</p>
<div class="mb-4">
<label for="programmingLanguageSelect" class="form-label">Select Programming Languages:</label>
<P11SelectMultiple TItem="string" TValue="string"
Id="programmingLanguageSelect"
@bind-Value="selectedProgrammingLanguages"
OnChanged="OnProgrammingLanguagesChanged"
Items="programmingLanguageOptions"
ItemValueExpression="lang => lang"
ItemTextExpression="lang => lang"
PlaceholderText="-- Choose languages --"
AriaLabel="Select programming languages dropdown">
</P11SelectMultiple>
<p class="mt-2">
Selected Languages (via OnChanged):
<strong>
@(selectedProgrammingLanguages != null && selectedProgrammingLanguages.Any()
? string.Join(", ", selectedProgrammingLanguages)
: "None")
</strong>
</p>
@if (!string.IsNullOrEmpty(programmingLanguagesChangedMessage))
{
<p class="text-info">@programmingLanguagesChangedMessage</p>
}
</div>@code {
// Properties for OnChanged event example
private ICollection<string> selectedProgrammingLanguages = new List<string>();
private string? programmingLanguagesChangedMessage;
private List<string> programmingLanguageOptions = new() { "C#", "JavaScript", "Python", "Java", "TypeScript", "Go" };
private void OnProgrammingLanguagesChanged(ICollection<string> newValues)
{
// selectedProgrammingLanguages is already updated by @bind-Value.
// We use newValues here to demonstrate the event payload.
programmingLanguagesChangedMessage = $"Sprachen geändert zu: {string.Join(", ", newValues ?? new List<string>())} um {DateTime.Now:HH:mm:ss}";
Console.WriteLine($"Programming languages changed to: {string.Join(", ", newValues ?? new List<string>())}");
}
}Component API
| Parameter | Type | Default | Description |
|---|---|---|---|
Items |
IEnumerable<TItem>? |
null |
Gets or sets the collection of items to display in the select dropdown. |
ItemValueExpression |
Expression<Func<TItem, TValue>>? |
null |
Gets or sets an expression that specifies which property of TItem should be used as the value for each option. This is the preferred way over ItemValueField for type safety and AOT/trimming compatibility. |
ItemTextExpression |
Expression<Func<TItem, string>>? |
null |
Gets or sets an expression that specifies which property of TItem should be used as the display text for each option. This is the preferred way over ItemTextField for type safety and AOT/trimming compatibility. |
ItemValueField |
string? |
null |
Gets or sets the name of the property in TItem to use as the value for each option. Use ItemValueExpression for better type safety and AOT/trimming compatibility. |
ItemTextField |
string? |
null |
Gets or sets the name of the property in TItem to use as the display text for each option. Use ItemTextExpression for better type safety and AOT/trimming compatibility. |
Id |
string? |
null |
Gets or sets the HTML 'id' attribute for the select element. Recommended for accessibility, especially when used with a <label>. |
Name |
string? |
null |
Gets or sets the HTML 'name' attribute for the select element. |
CssClass |
string? |
null |
Gets or sets additional CSS classes to apply to the select element. |
IsDisabled |
bool |
false |
Gets or sets a value indicating whether the select element should be disabled. |
AriaLabel |
string? |
null |
Gets or sets the ARIA label for accessibility. Provides a descriptive label for screen readers. Important if no visual label is associated via 'id' or 'for'. |
Title |
string? |
null |
Gets or sets the HTML 'title' attribute for the select element. Provides a tooltip on hover and can act as a fallback accessible name. |
PlaceholderText |
string? |
null |
Gets or sets the text for a default placeholder option. |
PlaceholderValue |
string |
string.Empty |
Gets or sets the value for the default placeholder option. |
PlaceholderIsDisabled |
bool |
true |
Gets or sets a value indicating whether the placeholder option should be disabled (not selectable). |
NoOptionsText |
string |
\"No options available\" |
Gets or sets the text to display when no options are available (and no placeholder or ChildContent is provided). |
ChildContent |
RenderFragment? |
null |
Gets or sets the content to render inside the <select> element, typically used to define custom <option> elements manually. |
SkipValidation |
bool |
false |
Gets or sets a value indicating whether to skip the internal configuration validation checks. |
| Events | |||
OnChanged |
EventCallback<ICollection<TValue>> |
- | An EventCallback that is invoked when the selected values of the component change. The callback receives the new collection of values as its argument. This complements the @bind-Value parameter. |