Tworzenie formularza w CloudFlow
Formularze w CloudFlow służą do edycji rekordów. Używają komponentu CFForm i dziedziczą po CFComponentBase<T>.
Szablon formularza
@inherits CFComponentBase<[NAZWA_KLASY]>
<CFForm TItem="[NAZWA_KLASY]" Record="@Record" Expand="[RELACJE]">
<RadzenStack>
<RadzenRow>
<CFTextBox SizeMD="6" @bind-Value="@context.Name" Required="true" LabelText="Nazwa" />
<CFTextBox SizeMD="6" @bind-Value="@context.Code" LabelText="Kod" />
</RadzenRow>
<RadzenRow>
<CFNumeric SizeMD="4" @bind-Value="@context.Price" LabelText="Cena" />
<CFDropDown SizeMD="4" TValue="ProductStatus"
Data="@(Tools.GenerateDropdownList<ProductStatus>())"
@bind-Value="@context.Status"
TextProperty="Text"
ValueProperty="Value" />
</RadzenRow>
</RadzenStack>
</CFForm>
@code {
#nullable enable
}
Struktura CFForm
Komponent CFForm to główny wrapper formularza obsługujący walidację, zapis i anulowanie.
Parametry CFForm
| Parametr | Typ | Opis |
|---|---|---|
TItem | Type | Typ encji (musi dziedziczyć po CFEntity) |
Record | TItem? | Rekord do edycji (przekazany z gridu lub strony) |
Expand | string | Relacje do załadowania (rozdzielone przecinkami) |
Select | string | Pola do pobrania |
Filter | string | Filtr OData |
IsModal | bool | Czy formularz jest w modalu |
EnableAIFill | bool | Włącz wypełnianie AI |
Callbacki CFForm
| Callback | Typ | Opis |
|---|---|---|
OnSubmit | EventCallback | Po wysłaniu formularza |
OnCancel | EventCallback<MouseEventArgs> | Po anulowaniu |
OnLoad | EventCallback<TItem> | Po załadowaniu rekordu |
OnAfterCreate | EventCallback<TItem> | Po utworzeniu nowego rekordu |
OnAfterUpdate | EventCallback<TItem> | Po aktualizacji rekordu |
Komponenty formularza CF
CloudFlow dostarcza zestaw komponentów UI z automatyczną walidacją i lokalizacją.
CFTextBox - Pole tekstowe
<CFTextBox SizeMD="6"
@bind-Value="@context.Name"
Required="true"
LabelText="Nazwa produktu"
Placeholder="Wpisz nazwę..." />
CFTextArea - Pole wieloliniowe
<CFTextArea SizeMD="12"
@bind-Value="@context.Description"
LabelText="Opis"
Rows="5" />
CFNumeric - Pole numeryczne
<CFNumeric SizeMD="4"
@bind-Value="@context.Price"
LabelText="Cena"
Format="C2"
Min="0" />
CFDatePicker - Wybór daty
<CFDatePicker SizeMD="4"
@bind-Value="@context.StartDate"
Required="true"
LabelText="Data rozpoczęcia" />
CFDropDown - Lista rozwijana
<CFDropDown SizeMD="4"
TValue="ProductStatus"
Data="@(Tools.GenerateDropdownList<ProductStatus>())"
@bind-Value="@context.Status"
TextProperty="Text"
ValueProperty="Value"
LabelText="Status" />
CFDropDownDataGrid - Dropdown z gridem
Używany do wyboru rekordu z innej encji (relacja FK):
<CFDropDownDataGrid SizeMD="6"
TValue="Guid?"
@bind-Value="@context.CategoryId"
LabelText="Kategoria" />
CFCheckbox - Pole wyboru
<CFCheckbox @bind-Value="@context.IsActive"
LabelText="Aktywny" />
CFMask - Pole z maską
<CFMask SizeMD="4"
@bind-Value="@context.NIP"
LabelText="NIP"
Mask="**********"
CharacterPattern="[0-9]" />
CFRadioButton - Przyciski radio
<CFRadioButton TValue="PaymentMethod"
@bind-Value="@context.PaymentMethod"
Data="@paymentMethods"
TextProperty="Name"
ValueProperty="Value" />
Wspólne parametry komponentów
| Parametr | Typ | Opis |
|---|---|---|
@bind-Value | TValue | Wiązanie wartości |
LabelText | string | Etykieta pola |
Required | bool | Czy pole jest wymagane |
Size / SizeMD / SizeLG | int | Szerokość kolumny (1-12) |
Disabled | bool | Czy pole jest wyłączone |
Placeholder | string | Tekst placeholder |
Responsywny layout
Używaj Size, SizeMD, SizeLG do tworzenia responsywnych layoutów. Wartości odpowiadają systemowi 12-kolumnowemu.
Zakładki w formularzu
Dla złożonych formularzy używaj zakładek:
<CFForm TItem="Product" Record="@Record" Expand="Category,Variants">
<RadzenStack>
<RadzenRow>
<RadzenTabs RenderMode="Radzen.TabRenderMode.Client"
TabPosition="TabPosition.Left"
class="w-100">
<Tabs>
<RadzenTabsItem Text="Dane podstawowe" Icon="description">
<RadzenStack>
<RadzenRow>
<CFTextBox SizeMD="6" @bind-Value="@context.Name"
Required="true" LabelText="Nazwa" />
<CFTextBox SizeMD="6" @bind-Value="@context.Code"
LabelText="Kod" />
</RadzenRow>
</RadzenStack>
</RadzenTabsItem>
<RadzenTabsItem Text="Ceny" Icon="attach_money">
<RadzenRow>
<CFNumeric SizeMD="4" @bind-Value="@context.Price"
LabelText="Cena netto" />
<CFNumeric SizeMD="4" @bind-Value="@context.VatRate"
LabelText="Stawka VAT %" />
</RadzenRow>
</RadzenTabsItem>
<RadzenTabsItem Text="Warianty" Icon="inventory_2">
@* Embedded grid *@
</RadzenTabsItem>
</Tabs>
</RadzenTabs>
</RadzenRow>
</RadzenStack>
</CFForm>
Embedded DataGrid (relacje)
Dla edycji kolekcji podrzędnych (np. pozycje zamówienia):
<CFDataGridEmbedded TItem="ProductVariant"
TForm="DummyForm"
@bind-Data="context.Variants"
ParentObject="context">
<ChildContent Context="variants">
<RadzenDataGridColumn TItem="ProductVariant" Property="Name" Title="Nazwa">
<EditTemplate Context="row">
<RadzenTextBox @bind-Value="@row.Name" class="rz-w-100" />
</EditTemplate>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="ProductVariant" Property="SKU" Title="SKU">
<EditTemplate Context="row">
<RadzenTextBox @bind-Value="@row.SKU" class="rz-w-100" />
</EditTemplate>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="ProductVariant" Property="Price" Title="Cena">
<EditTemplate Context="row">
<RadzenNumeric @bind-Value="@row.Price" class="rz-w-100" />
</EditTemplate>
</RadzenDataGridColumn>
</ChildContent>
</CFDataGridEmbedded>
DummyForm
TForm="DummyForm" używamy gdy nie potrzebujemy osobnego formularza dla encji podrzędnej - edycja inline w gridzie.
Logika w code block
@code {
#nullable enable
// Pola lokalne
private bool isBusy = false;
private IEnumerable<Category> categories = [];
// Inicjalizacja
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
categories = await DatabaseService.GetAsync<Category>();
}
// Metody pomocnicze
private async Task LoadExternalData()
{
isBusy = true;
try
{
// Logika ładowania danych z zewnętrznego źródła
var data = await ExternalApi.FetchDataAsync();
// Aktualizacja rekordu
}
finally
{
isBusy = false;
StateHasChanged();
}
}
// Walidacja niestandardowa
private bool ValidateNIP(string? nip)
{
if (string.IsNullOrEmpty(nip)) return true;
// Logika walidacji NIP
return nip.Length == 10;
}
}
Przykład kompletnego formularza
@inherits CFComponentBase<Product>
<CFForm TItem="Product" Record="@Record" Expand="Category,Variants">
<RadzenStack>
<RadzenRow>
<RadzenTabs RenderMode="Radzen.TabRenderMode.Client"
TabPosition="TabPosition.Left"
class="w-100">
<Tabs>
<RadzenTabsItem Text="Dane podstawowe" Icon="description">
<RadzenStack>
<RadzenRow>
<CFTextBox SizeMD="6" @bind-Value="@context.Name"
Required="true"
LabelText="@ClassLocalizer["Name"]" />
<CFTextBox SizeMD="3" @bind-Value="@context.Code"
LabelText="@ClassLocalizer["Code"]" />
<CFDropDown SizeMD="3"
TValue="ProductStatus"
Data="@(Tools.GenerateDropdownList<ProductStatus>())"
@bind-Value="@context.Status"
TextProperty="Text"
ValueProperty="Value"
LabelText="@ClassLocalizer["Status"]" />
</RadzenRow>
<RadzenRow>
<CFNumeric SizeMD="4" @bind-Value="@context.Price"
LabelText="@ClassLocalizer["Price"]" />
<CFNumeric SizeMD="4" @bind-Value="@context.Quantity"
LabelText="@ClassLocalizer["Quantity"]" />
<CFDropDownDataGrid SizeMD="4"
TValue="Guid?"
@bind-Value="@context.CategoryId"
LabelText="@ClassLocalizer["Category"]" />
</RadzenRow>
<RadzenRow>
<CFTextArea SizeMD="12"
@bind-Value="@context.Description"
LabelText="@ClassLocalizer["Description"]"
Rows="4" />
</RadzenRow>
</RadzenStack>
</RadzenTabsItem>
<RadzenTabsItem Text="Warianty" Icon="inventory_2">
<CFDataGridEmbedded TItem="ProductVariant"
TForm="DummyForm"
@bind-Data="context.Variants"
ParentObject="context">
<ChildContent Context="variants">
<RadzenDataGridColumn TItem="ProductVariant"
Property="Name"
Title="Nazwa">
<EditTemplate Context="row">
<RadzenTextBox @bind-Value="@row.Name"
class="rz-w-100" />
</EditTemplate>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="ProductVariant"
Property="SKU"
Title="SKU">
<EditTemplate Context="row">
<RadzenTextBox @bind-Value="@row.SKU"
class="rz-w-100" />
</EditTemplate>
</RadzenDataGridColumn>
</ChildContent>
</CFDataGridEmbedded>
</RadzenTabsItem>
</Tabs>
</RadzenTabs>
</RadzenRow>
</RadzenStack>
</CFForm>
@code {
#nullable enable
}
Następne kroki
- Tworzenie strony - Jak stworzyć stronę z listą rekordów
- Komponenty CF - Szczegółowa dokumentacja komponentów