true-perfect-code
Version: 1.1.69

P11Select Component

The P11Select component provides a single-selection dropdown list, wrapping the native HTML <select> element. It integrates Bootstrap's .form-select class for modern styling and offers flexible options for data binding, placeholder text, and accessibility.
Note: You can populate options either by providing an Items collection along with ItemValueExpression/ItemTextExpression (recommended for type safety and AOT) or by using ItemValueField/ItemTextField (less type-safe). Alternatively, you can define options manually using ChildContent.


P11Select Component Examples

These examples demonstrate various configurations and functionalities of the P11Select component, showcasing its flexibility for different use cases.

1. Standard Usage with List of Objects

Selecting a name from a list of Person objects.

Selected Person ID: Nothing selected

Implementation

<h4 class="mb-3">1. Standard Usage with List of Objects</h4>
<p>Selecting a name from a list of <code>Person</code> objects.</p>
<div class="mb-4">
    <label for="personSelect" class="form-label">Select a person:</label>
    <P11Select TItem="Person" TValue="int?"
               Id="personSelect"
               @bind-Value="selectedPersonId"
               Items="people"
               ItemValueExpression="p => p.Id"
               ItemTextExpression="p => p.Name"
               PlaceholderText="-- Please select --"
               AriaLabel="Select person dropdown"
               CssClass="form-select-lg">
    </P11Select>
    <p class="mt-2">Selected Person ID: <strong>@(selectedPersonId.HasValue? selectedPersonId.ToString() : "Nothing selected")</strong></p>
</div>
@code {
    public class Person
    {
        public int Id { get; set; }
        public string? Name { get; set; }
        public string? City { get; set; }
    }

    // Data for examples
    private List<Person> people = 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
    private int? selectedPersonId;
}


2. Usage with Enum

Selecting a priority from an enum.

Selected Priority: Nothing selected

Implementation

<h4 class="mb-3">2. Usage with Enum</h4>
<p>Selecting a priority from an <code>enum</code>.</p>
<div class="mb-4">
    <label for="prioritySelect" class="form-label">Select a priority:</label>
    <P11Select TItem="Priority" TValue="Priority?"
               Id="prioritySelect"
               @bind-Value="selectedPriority"
               Items="Enum.GetValues<Priority>()"
               ItemValueExpression="p => p"
               ItemTextExpression="p => p.ToString()"
               PlaceholderText="-- Select Priority --"
               AriaLabel="Select priority dropdown">
    </P11Select>
    <p class="mt-2">Selected Priority: <strong>@(selectedPriority.HasValue? selectedPriority.ToString() : "Nothing selected")</strong></p>
</div>
@code {
    public enum Priority
    {
        Low,
        Medium,
        High,
        Urgent
    }

    // Properties for binding
    private Priority? selectedPriority;
}


3. Manual Options (ChildContent)

Direct rendering of <option> tags within the component.

Selected City: Nothing selected

Implementation

<h4 class="mb-3">3. Manual Options (ChildContent)</h4>
<p>Direct rendering of <code>&lt;option&gt;</code> tags within the component.</p>
<div class="mb-4">
    <label for="citySelect" class="form-label">Select a city:</label>
    <P11Select TItem="string" TValue="string"
               Id="citySelect"
               @bind-Value="selectedCity"
               PlaceholderText="Select a city manually"
               AriaLabel="Select city dropdown">
        <option value="BER">Berlin</option>
        <option value="MUN">Munich</option>
        <option value="HAM">Hamburg</option>
        <option value="COL">Cologne</option>
    </P11Select>
    <p class="mt-2">Selected City: <strong>@(string.IsNullOrEmpty(selectedCity) ? "Nothing selected" : selectedCity)</strong></p>
</div>
@code {
    private string? selectedCity;
}


4. Disabled Select

A select field that is not interactive.

Disabled Selection: 2

Implementation

<h4 class="mb-3">4. Disabled Select</h4>
<p>A select field that is not interactive.</p>
<div class="mb-4">
    <label for="disabledSelect" class="form-label">Disabled Selection:</label>
    <P11Select TItem="Person" TValue="int?"
               Id="disabledSelect"
               @bind-Value="disabledSelectedPersonId"
               Items="people"
               ItemValueExpression="p => p.Id"
               ItemTextExpression="p => p.Name"
               IsDisabled="true"
               PlaceholderText="Selection disabled"
               AriaLabel="Disabled person dropdown">
    </P11Select>
    <p class="mt-2">Disabled Selection: <strong>@(disabledSelectedPersonId.HasValue? disabledSelectedPersonId.ToString() : "Nothing selected")</strong></p>
</div>
@code {
    public class Person
    {
        public int Id { get; set; }
        public string? Name { get; set; }
        public string? City { get; set; }
    }

    // Data for examples
    private List<Person> people = 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
    private int? disabledSelectedPersonId = 2; // Pre-selected for disabled example
}


5. Validation in EditForm

Demonstrates integration with Blazor's EditForm and validation mechanisms.

Validation Status: Waiting for submission...



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.

TpcSelect Configuration Error:

P11Select AOT/Trimming Warning: The TValue type 'Int16' is not explicitly handled by a direct parsing method. Parsing will fall back to 'Convert.ChangeType', which relies on reflection and may cause issues with AOT (Ahead-of-Time) compilation and trimming. Consider using one of the explicitly supported types (String, Int32, Int64, Guid, Enum) or implement explicit parsing logic for this type if AOT compatibility is critical.

This is only visible during development. Please correct the parameters or set SkipValidation to true to suppress this warning.

Selected short number: Nothing selected

Implementation

<h4 class="mb-3">5. Validation in EditForm</h4>
<p>Demonstrates integration with Blazor's <code>EditForm</code> and validation mechanisms.</p>
<div class="mb-4">
    <EditForm Model="validationModel" OnValidSubmit="HandleValidSubmit2" OnInvalidSubmit="HandleInvalidSubmit2">
        <DataAnnotationsValidator />
        <ValidationSummary />

        <div class="mb-3">
            <label for="requiredPersonSelect" class="form-label">Required Field Person:</label>
            <P11Select TItem="Person" TValue="int?"
                       Id="requiredPersonSelect"
                       @bind-Value="validationModel.SelectedRequiredPersonId"
                       Items="people"
                       ItemValueExpression="p => p.Id"
                       ItemTextExpression="p => p.Name"
                       PlaceholderText="-- Select Required Field --"
                       AriaLabel="Required Person Dropdown">
            </P11Select>
            <ValidationMessage For="@(() => validationModel.SelectedRequiredPersonId)" />
        </div>

        <div class="mb-3">
            <label for="requiredPrioritySelect" class="form-label">Required Field Priority:</label>
            <P11Select TItem="Priority" TValue="Priority?"
                       Id="requiredPrioritySelect"
                       @bind-Value="validationModel.SelectedRequiredPriority"
                       Items="Enum.GetValues<Priority>()"
                       ItemValueExpression="p => p"
                       ItemTextExpression="p => p.ToString()"
                       PlaceholderText="-- Select Required Field --"
                       AriaLabel="Required Priority Dropdown">
            </P11Select>
            <ValidationMessage For="@(() => validationModel.SelectedRequiredPriority)" />
        </div>

        <button type="submit" class="btn btn-primary">Submit Form</button>
        <p class="mt-2">Validation Status: <strong>@validationStatus</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="shortNumberSelect" class="form-label">Select a short number:</label>
    <P11Select TItem="short" TValue="short"
               Id="shortNumberSelect"
               @bind-Value="selectedShortNumber"
               PlaceholderText="Select a short number"
               AriaLabel="Dropdown for short number selection"
               SkipValidation=false>
        <option value="10">Ten</option>
        <option value="20">Twenty</option>
        <option value="30">Thirty</option>
        <option value="40">Forty</option>
    </P11Select>
    <p class="mt-2">Selected short number: <strong>@(selectedShortNumber == 0 ? "Nothing selected" : selectedShortNumber.ToString())</strong></p>
</div>
@* You may need the using *@
@* @using System.ComponentModel.DataAnnotations *@
@code {
    public enum Priority
    {
        Low,
        Medium,
        High,
        Urgent
    }

    public class Person
    {
        public int Id { get; set; }
        public string? Name { get; set; }
        public string? City { get; set; }
    }

    // Data for examples
    private List<Person> people = 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" }
    };

    // Validation Model (often in a separate .cs file, e.g., Models/ValidationTestModel.cs)
    public class ValidationTestModel
    {
        [Required(ErrorMessage = "Please select a person.")]
        public int? SelectedRequiredPersonId { get; set; }

        [Required(ErrorMessage = "Please select a priority.")]
        public Priority? SelectedRequiredPriority { get; set; }
    }

    // Model for validation example
    private ValidationTestModel validationModel = new ValidationTestModel();
    private string validationStatus = "Waiting for submission...";
    private short selectedShortNumber { get; set; } = 0;

    private void HandleValidSubmit2()
    {
        validationStatus = "Form is VALID!";
        Console.WriteLine($"Validation successful. Person: {validationModel.SelectedRequiredPersonId}, Priority: {validationModel.SelectedRequiredPriority}");
    }

    private void HandleInvalidSubmit2()
    {
        validationStatus = "Form is INVALID!";
        Console.WriteLine("Validation failed.");
    }
}


6. OnChanged Event Example

This example demonstrates how to use the OnChanged event to react to changes in the selected value. The current selection is displayed immediately after a change.

Selected Fruit (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 value. The current selection is displayed immediately after a change.</p>
<div class="mb-4">
    <label for="fruitSelect" class="form-label">Select a fruit:</label>
    <P11Select TItem="string" TValue="string"
               Id="fruitSelect"
               @bind-Value="selectedFruit"
               OnChanged="OnFruitChanged"
               Items="fruitOptions"
               ItemValueExpression="f => f"
               ItemTextExpression="f => f"
               PlaceholderText="-- Choose a fruit --"
               AriaLabel="Select fruit dropdown">
    </P11Select>
    <p class="mt-2">Selected Fruit (via OnChanged): <strong>@(selectedFruit ?? "None")</strong></p>
    @if (!string.IsNullOrEmpty(fruitChangedMessage))
    {
        <p class="text-info">@fruitChangedMessage</p>
    }
</div>
@code {
    // Properties for binding
    private string? selectedFruit; // For OnChanged example
    private string? fruitChangedMessage; // For OnChanged example

    // Options for OnChanged example
    private List<string> fruitOptions = new() { "Apple", "Banana", "Orange", "Grape" };

    // Event handlers
    private void OnFruitChanged(string? newFruit)
    {
        // selectedFruit is already updated by @bind-Value.
        // We use newFruit here to demonstrate the event payload.
        fruitChangedMessage = $"Fruit changed to: {newFruit ?? "Nothing"} at {DateTime.Now:HH:mm:ss}";
        Console.WriteLine($"Fruit changed to: {newFruit}");
    }
}


Component API

Parameter Type Default Description
Items IEnumerable<TItem>? null Gets or sets the collection of items to display in the component.
ItemValueExpression Expression<Func<TItem, TValue>>? null Gets or sets an expression that specifies how to extract the value from an item of type TItem. This is type-safe and preferred for AOT/trimming compatibility.
ItemTextExpression Expression<Func<TItem, string>>? null Gets or sets an expression that specifies how to extract the display text from an item of type TItem. This is type-safe and preferred for AOT/trimming compatibility.
ItemValueField string? null Gets or sets the name of the property in TItem to use as the value for each item. 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 item. Use ItemTextExpression for better type safety and AOT/trimming compatibility.
Id string? null Gets or sets the HTML 'id' attribute for the select element.
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 is disabled.
AriaLabel string? null Gets or sets the ARIA label for accessibility, providing a descriptive label for screen readers.
Title string? null Gets or sets the HTML 'title' attribute for the select element, providing a tooltip on hover.
PlaceholderText string? null Gets or sets the text for a default placeholder option in the select element.
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.
NoOptionsText string \"No options available\" Gets or sets the text to display when no options are available in the select element.
ChildContent RenderFragment? null Gets or sets the content to render inside the select element, typically used for custom option elements or when manually providing <option> tags.
SkipValidation bool false Gets or sets a value indicating whether to skip internal configuration validation checks.
Events
OnChanged EventCallback<TValue> - Gets or sets the custom event callback for when the selected value changes. This allows consumers to react to changes, similar to a standard 'onChange' event.
An unhandled error has occurred. Reload 🗙