Descriere Generală
FODInputSelect
este componenta dropdown select pentru FOD.Components. Oferă suport pentru binding bidirecțional, validare integrată cu EditForm, localizare automată pentru enum-uri și opțiune default configurabilă. Componenta moștenește din FODSelectableFormComponent<T>
și suportă tipuri generice.
Utilizare de Bază
<!-- Select simplu -->
<FODInputSelect @bind-Value="selectedCountry"
Options="@countries"
Label="Țară" />
<!-- Select cu enum -->
<FODInputSelect @bind-Value="status"
Label="Status Comandă"
Options="@GetEnumOptions<OrderStatus>()" />
<!-- Select cu opțiune default personalizată -->
<FODInputSelect @bind-Value="selectedCity"
Options="@cities"
Label="Oraș"
DefaultOptionText="-- Alegeți orașul --" />
@code {
private string selectedCountry;
private OrderStatus status;
private string selectedCity;
private List<SelectableItem<string>> countries = new()
{
new("MD", "Moldova"),
new("RO", "România"),
new("UA", "Ucraina")
};
private List<SelectableItem<string>> cities = new()
{
new("chisinau", "Chișinău"),
new("balti", "Bălți"),
new("tiraspol", "Tiraspol")
};
}
Atribute Disponibile
Atribut |
Tip |
Default |
Descriere |
Value |
T |
- |
Valoarea selectată |
Options |
IEnumerable> |
- |
Lista de opțiuni |
Label |
string |
- |
Eticheta select-ului |
DefaultOption |
bool |
false |
Selectează prima opțiune automat |
DefaultOptionText |
string |
"Select..." |
Text pentru opțiunea default |
Required |
bool |
false |
Câmp obligatoriu |
Readonly |
bool |
false |
Doar citire |
CssClass |
string |
- |
Clase CSS adiționale |
isInvalid |
bool |
false |
Stare de invalidare |
Id |
string |
Guid |
ID unic pentru element |
Name |
string |
- |
Numele câmpului |
ValueExpression |
Expression> |
- |
Expresie pentru validare |
OnValueChanged |
EventCallback |
- |
Eveniment la schimbare |
For |
Expression> |
- |
Expresie pentru EditForm |
Evenimente
Eveniment |
Tip |
Descriere |
OnValueChanged |
EventCallback |
Declanșat la schimbarea selecției |
OnChange |
ChangeEventArgs |
Handler intern pentru schimbare |
Metode Publice
Metodă |
Returnează |
Descriere |
GetName() |
string |
Returnează numele câmpului |
GetDescription(SelectableItem) |
string |
Obține descrierea localizată |
GetLocalizedString(Type, string) |
string |
Obține string localizat |
Exemple Avansate
Select cu Enum Localizat
<FODInputSelect @bind-Value="model.UserRole"
For="@(() => model.UserRole)"
Label="Rol Utilizator"
Options="@GetLocalizedRoleOptions()"
Required="true" />
@code {
private UserModel model = new();
public enum UserRole
{
[Display(Name = "Role_Admin", ResourceType = typeof(Resources.Roles))]
Administrator,
[Display(Name = "Role_Operator", ResourceType = typeof(Resources.Roles))]
Operator,
[Display(Name = "Role_Guest", ResourceType = typeof(Resources.Roles))]
Guest
}
private List<SelectableItem<UserRole>> GetLocalizedRoleOptions()
{
return Enum.GetValues<UserRole>()
.Select(role => new SelectableItem<UserRole>(role, GetRoleDisplayName(role)))
.ToList();
}
}
Select cu Validare
<EditForm Model="@order" OnValidSubmit="@HandleSubmit">
<DataAnnotationsValidator />
<FODInputSelect @bind-Value="order.PaymentMethod"
For="@(() => order.PaymentMethod)"
Label="Metoda de plată"
Options="@paymentMethods"
Required="true"
isInvalid="@(validationErrors.ContainsKey("PaymentMethod"))" />
<ValidationMessage For="@(() => order.PaymentMethod)" />
<FODInputSelect @bind-Value="order.DeliveryAddress"
For="@(() => order.DeliveryAddress)"
Label="Adresa de livrare"
Options="@addresses"
DefaultOptionText="-- Selectați adresa --" />
<FodButton Type="submit">Plasează Comanda</FodButton>
</EditForm>
@code {
private OrderModel order = new();
private Dictionary<string, string> validationErrors = new();
private List<SelectableItem<string>> paymentMethods = new()
{
new("card", "Card Bancar"),
new("cash", "Numerar la livrare"),
new("transfer", "Transfer Bancar")
};
public class OrderModel
{
[Required(ErrorMessage = "Selectați metoda de plată")]
public string PaymentMethod { get; set; }
public string DeliveryAddress { get; set; }
}
}
Select Cascadă
<FODInputSelect @bind-Value="selectedCountry"
Label="Țară"
Options="@countries"
OnValueChanged="@OnCountryChanged" />
@if (regions?.Any() == true)
{
<FODInputSelect @bind-Value="selectedRegion"
Label="Regiune"
Options="@regions"
OnValueChanged="@OnRegionChanged" />
}
@if (cities?.Any() == true)
{
<FODInputSelect @bind-Value="selectedCity"
Label="Oraș"
Options="@cities" />
}
@code {
private string selectedCountry;
private string selectedRegion;
private string selectedCity;
private List<SelectableItem<string>> countries;
private List<SelectableItem<string>> regions;
private List<SelectableItem<string>> cities;
protected override async Task OnInitializedAsync()
{
countries = await LoadCountries();
}
private async Task OnCountryChanged(string country)
{
selectedRegion = null;
selectedCity = null;
regions = await LoadRegions(country);
cities = null;
}
private async Task OnRegionChanged(string region)
{
selectedCity = null;
cities = await LoadCities(selectedCountry, region);
}
}
Select cu Obiecte Complexe
<FODInputSelect @bind-Value="selectedEmployee"
Label="Responsabil"
Options="@employeeOptions"
DefaultOptionText="-- Fără responsabil --" />
@if (selectedEmployee != null)
{
<div class="selected-info mt-3">
<strong>Selectat:</strong> @selectedEmployee.Name<br/>
<strong>Departament:</strong> @selectedEmployee.Department<br/>
<strong>Email:</strong> @selectedEmployee.Email
</div>
}
@code {
private Employee selectedEmployee;
private List<SelectableItem<Employee>> employeeOptions;
protected override async Task OnInitializedAsync()
{
var employees = await EmployeeService.GetActiveEmployees();
employeeOptions = employees
.Select(e => new SelectableItem<Employee>(
e,
$"{e.Name} - {e.Department}"
))
.ToList();
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Department { get; set; }
public string Email { get; set; }
}
}
Select cu Grupare Vizuală
<FODInputSelect @bind-Value="selectedProduct"
Label="Produs"
Options="@productOptions"
CssClass="grouped-select">
<ChildContent>
<option value="">-- Selectați produsul --</option>
@foreach (var category in groupedProducts)
{
<optgroup label="@category.Key">
@foreach (var product in category.Value)
{
<option value="@product.Id">@product.Name - @product.Price.ToString("C")</option>
}
</optgroup>
}
</ChildContent>
</FODInputSelect>
@code {
private string selectedProduct;
private Dictionary<string, List<Product>> groupedProducts;
protected override async Task OnInitializedAsync()
{
var products = await ProductService.GetAll();
groupedProducts = products.GroupBy(p => p.Category)
.ToDictionary(g => g.Key, g => g.ToList());
}
}
Select cu Stil Personalizat
<style>
.custom-select-wrapper .fod-select select {
border-radius: 20px;
padding: 10px 20px;
border: 2px solid #e0e0e0;
transition: all 0.3s ease;
}
.custom-select-wrapper .fod-select select:focus {
border-color: var(--fod-primary);
box-shadow: 0 0 0 0.2rem rgba(var(--fod-primary-rgb), 0.25);
}
.custom-select-wrapper .fod-select select.invalid {
border-color: var(--fod-error);
background-color: rgba(var(--fod-error-rgb), 0.05);
}
</style>
<div class="custom-select-wrapper">
<FODInputSelect @bind-Value="selectedOption"
Label="Opțiune Stilizată"
Options="@options"
CssClass="custom-styled" />
</div>
Select cu Pre-selectare Condiționată
<FODInputSelect @bind-Value="model.PreferredLanguage"
Label="Limba preferată"
Options="@languages"
DefaultOption="true" />
@code {
private UserPreferences model = new();
private List<SelectableItem<string>> languages;
protected override async Task OnInitializedAsync()
{
// Încarcă limbile disponibile
languages = new List<SelectableItem<string>>
{
new("ro", "Română"),
new("en", "English"),
new("ru", "Русский")
};
// Setează limba bazată pe browser sau preferințe salvate
model.PreferredLanguage = await GetUserPreferredLanguage() ?? "ro";
}
}
Componente Asociate
FODInputWrapper
- Container pentru elementele de formular
FODSelectableFormComponent<T>
- Clasă de bază pentru componente cu selecție
ValidationMessage
- Afișare mesaje de validare
SelectableItem<T>
- Model pentru opțiuni
Stilizare
Clase CSS
.fod-select
.custom-select
.form-control
.invalid
Personalizare Aspect
/* Select personalizat */
.fod-select select {
appearance: none;
background-image: url("data:image/svg+xml,..."); /* Arrow custom */
background-repeat: no-repeat;
background-position: right 0.75rem center;
background-size: 16px 12px;
padding-right: 2.5rem;
}
/* Focus state */
.fod-select select:focus {
border-color: var(--fod-primary);
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(var(--fod-primary-rgb), 0.25);
}
/* Invalid state */
.fod-select select.invalid {
border-color: var(--fod-error);
background-image: url("data:image/svg+xml,..."); /* Error icon */
}
/* Disabled state */
.fod-select select:disabled {
background-color: #e9ecef;
opacity: 0.65;
}
Note și Observații
- Generic Type - Suportă orice tip T care poate fi serializat
- Enum Support - Suport automat pentru Display attributes
- Null Handling - Prima opțiune poate fi null/empty
- Validation - Integrare completă cu EditForm
- Accessibility - ID-uri unice generate automat
Bune Practici
- Folosiți
For
pentru integrare corectă cu validarea
- Setați
DefaultOptionText
descriptiv
- Limitați numărul de opțiuni (folosiți filtrat pentru liste mari)
- Grupați opțiunile logic când sunt multe
- Adăugați tooltips pentru opțiuni complexe
- Validați pe server selecțiile critice
- Folosiți
DefaultOption
doar când are sens logic
Concluzie
FODInputSelect oferă o implementare robustă pentru dropdown-uri în aplicații Blazor. Cu suport pentru tipuri generice, localizare automată și integrare completă cu sistemul de validare, componenta acoperă majoritatea necesităților pentru selecție din liste în formulare.