form & input overview

main
Peace 10 months ago
parent 1248f1d93a
commit 991b0de353
  1. 4
      BlazorFluentUI/Components/Layout/NavMenu.razor
  2. 110
      BlazorFluentUI/Components/Pages/FormInputOverView.razor
  3. 2
      BlazorFluentUI/Components/Pages/LayoutStack.razor
  4. 2
      BlazorFluentUI/Components/_Imports.razor
  5. 11
      BlazorFluentUI/Models/Country.cs
  6. 35
      BlazorFluentUI/Models/Starship.cs
  7. 3
      BlazorFluentUI/Program.cs
  8. 74
      BlazorFluentUI/Services/CountryService.cs

@ -21,6 +21,10 @@
<FluentNavLink Href="layoutsplitter" Icon="@(new Icons.Regular.Size20.SplitVertical())" IconColor="Color.Accent">Splitter</FluentNavLink>
<FluentNavLink Href="layoutstack" Icon="@(new Icons.Regular.Size20.Stack())" IconColor="Color.Accent">Stack</FluentNavLink>
</FluentNavGroup>
<FluentNavGroup Icon="@(new Icons.Regular.Size20.Form())" Expanded="false" Title="Form & Input">
<FluentNavLink Href="forminputoverview" Icon="@(new Icons.Regular.Size20.Eye())" IconColor="Color.Accent">Overview</FluentNavLink>
</FluentNavGroup>
</FluentNavMenu>
</nav>
</div>

@ -0,0 +1,110 @@
@page "/forminputoverview"
@inject CountryService countryService;
@rendermode RenderMode.InteractiveServer
<FluentLabel Typo="Typography.H3">Basic Fluent UI Form</FluentLabel>
<FluentDivider class="mt-1 mb-3" Role="DividerRole.Separator" />
<FluentLabel Typo="Typography.Body">
This is an example of the Fluent UI.
The <code>FluentValidationSummary</code> and <code>FluentValidationMessage</code> give feedback on the state of the form.
Is uses <code>Starship</code> model form <a href="https://learn.microsoft.com/en-us/aspnet/core/blazor/forms/input-components?view=aspnetcore-8.0#example-form">Standard Documentation</a>.
</FluentLabel>
<FluentCard Class="mt-3" Width="auto" Height="auto">
<FluentLabel Class="mt2" Typo="Typography.H4">Starfleet Starship Database</FluentLabel>
<p>
This form uses the Fluent UI input components.
It uses a <code>DataAnnotationsValidator</code>, a <code>FluentValidationSummary</code> and <code>FluentValidationMessage</code>s.;
</p>
<FluentLabel Class="mt-4" Typo="Typography.H4">New Ship Entry Form</FluentLabel>
<EditForm class="mt-2" Model="@starship" OnValidSubmit="@HandleValidSubmit" FormName="starship_fluent_entry">
<DataAnnotationsValidator/>
<FluentValidationSummary/>
<FluentStack Orientation="Orientation.Vertical">
<div>
<FluentTextField Name="identifier" @bind-Value="@starship.Identifier" Label="Identifier" Required/>
<FluentValidationMessage For="@(() => starship.Identifier)"/>
</div>
<div>
<FluentTextField Name="description" @bind-Value="@starship.Description" Label="Description (optional)" />
<FluentValidationMessage For="@(() => starship.Description)" />
</div>
<div>
<FluentAutocomplete TOption="Country"
Name="countries"
AutoComplete="on"
Label="Select countries"
Width="250px"
Placeholder="Select countries"
OnOptionsSearch="@OnSearchCountryAsync"
MaximumSelectedOptions="3"
OptionText="@(item => item.Name)"
Multiple="true"
@bind-SelectedOptions="@starship.Countries" />
<FluentValidationMessage For="@(() => starship.Countries)"/>
</div>
<div>
<FluentSelect TOption="string" Name="class" Id="classification" @bind-Value="@starship.Classification" Label="Primary classification" Required>
<FluentOption Value="">Select classification...</FluentOption>
<FluentOption Value="Exploration">Exploration</FluentOption>
<FluentOption Value="Commerce">Commerce</FluentOption>
<FluentOption Value="Diplomacy">Diplomacy</FluentOption>
<FluentOption Value="Defense">Defense</FluentOption>
</FluentSelect>
<FluentValidationMessage For="@(() => starship.Classification)"/>
</div>
<div>
<FluentNumberField Name="accomodation" @bind-Value="@starship.MaximumAccomodation" Label="Maximum accomodation" Required/>
<FluentValidationMessage For="@(() => starship.MaximumAccomodation)"/>
</div>
<div>
<FluentCheckbox Name="approved" @bind-Value="starship.IsValidatedDesign" Required Label="Engineering approval" />
<FluentValidationMessage For="@(() => starship.IsValidatedDesign)" />
</div>
<div>
<FluentDatePicker Name="production_date" Id="proddate" @bind-Value="starship.ProductionDate" Label="Production Date" Required />
<FluentValidationMessage For="@(() => starship.ProductionDate)" />
</div>
<div>
<FluentSwitch Name="teleporter" @bind-value="starship.HasTeleporter" Label="Teleporter" CheckedMessage="Fully operational" UncheckedMessage="Under maintenance" />
<FluentValidationMessage For="@(() => starship.HasTeleporter)" />
</div>
<FluentButton Type="ButtonType.Submit" Appearance="Appearance.Accent">Submit</FluentButton>
</FluentStack>
</EditForm>
<FluentLabel Class="mt-3" Color="Color.Info"/>
</FluentCard>
@code {
[SupplyParameterFromForm]
Starship starship { get; set; } = new Starship();
string message = "";
protected override void OnInitialized()
{
starship.ProductionDate = DateTime.Now;
}
private async Task OnSearchCountryAsync(OptionsSearchEventArgs<Country> e)
{
var allCountry = await countryService.GetAllCountriesAsync();
e.Items = allCountry.Where(c => c.Name.StartsWith(e.Text, StringComparison.OrdinalIgnoreCase))
.OrderBy(c => c.Name);
}
private void HandleValidSubmit()
{
message = $"Message: HandleValidSubmit called.";
}
private void OnSubmit(Starship e)
{
}
}

@ -12,7 +12,9 @@
<FluentLabel class="my-3" Typo="Typography.H4">Characteristics</FluentLabel>
<FluentLabel Class="ms-2">
1. <code>Orientation</code>: The child components are controlled via the <code>Horizontal</code>(default) or <code>Vertical</code>.
<br />
2. <code>Alignment</code>: The child components are controlled via the <code>HorizontalAlignment</code> and <code>VerticalAlignment</code>.
<br />
3. <code>Spacing</code>: The child components are controlled via the <code>HorizontalGap</code> and <code>VerticalGap</code>.
</FluentLabel>

@ -9,4 +9,6 @@
@using Microsoft.JSInterop
@using BlazorFluentUI
@using BlazorFluentUI.Components
@using BlazorFluentUI.Models
@using BlazorFluentUI.Services

@ -0,0 +1,11 @@
namespace BlazorFluentUI.Models
{
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
}
}

@ -0,0 +1,35 @@
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
namespace BlazorFluentUI.Models
{
[RequiresUnreferencedCode("Necessary because of RangeAttribute usage")]
public class Starship
{
[Required]
[MinLength(3, ErrorMessage = "Identifier is too short")]
[StringLength(16, ErrorMessage = "Identifier is too long (16 character limit)")]
public string? Identifier { get; set; }
public string? Description { get; set; }
[Required(ErrorMessage = "Countries are required")]
public IEnumerable<Country> Countries { get; set; }
[Required(ErrorMessage = "A classification is required")]
public string? Classification { get; set; }
[Required]
[Range(1, 100000, ErrorMessage = "Accomodation invalid (1-100000)")]
public int MaximumAccomodation { get; set; }
[Required]
[Range(typeof(bool), "true", "true", ErrorMessage = "This form disallows unapproved ships")]
public bool IsValidatedDesign { get; set; }
[Required]
public DateTime? ProductionDate { get; set; }
public bool HasTeleporter { get; set; }
}
}

@ -1,5 +1,6 @@
using Microsoft.FluentUI.AspNetCore.Components;
using BlazorFluentUI.Components;
using BlazorFluentUI.Services;
var builder = WebApplication.CreateBuilder(args);
@ -14,6 +15,8 @@ builder.Services.AddRazorComponents(options =>
});
builder.Services.AddFluentUIComponents();
builder.Services.AddSingleton<CountryService>();
var app = builder.Build();
// Configure the HTTP request pipeline.

@ -0,0 +1,74 @@
using BlazorFluentUI.Models;
namespace BlazorFluentUI.Services
{
public class CountryService
{
private readonly List<Country> _countries = new List<Country>();
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
private readonly Random _random = new Random();
private readonly string[] _countryNames = { "Korea", "USA", "Canada", "Mexico", "Brazil", "UK", "Germany", "France", "Italy", "China", "Japan", "India", "Australia", "Russia", "Spain", "South Africa", "New Zealand", "Argentina", "Egypt", "Thailand", "Sweden", "Norway", "Denmark", "Finland", "Netherlands", "Belgium" };
public CountryService()
{
var randomCountryNames = _countryNames.OrderBy(x => Guid.NewGuid()).ToArray();
for (int i = 0; i < randomCountryNames.Length; i++)
{
var country = new Country
{
Id = i + 1,
Name = randomCountryNames[i],
};
_countries.Add(country);
}
}
public async Task<Country> GetCountryAsync(int id)
{
await _semaphore.WaitAsync();
try
{
return _countries.FirstOrDefault(c => c.Id == id);
}
finally
{
_semaphore.Release();
}
}
public async Task<IEnumerable<Country>> GetAllCountriesAsync()
{
await _semaphore.WaitAsync();
try
{
return _countries.ToList();
}
finally
{
_semaphore.Release();
}
}
//public async Task GenerateRandomCountriesAsync(int count)
//{
// await _semaphore.WaitAsync();
// try
// {
// for (int i = 0; i < count; i++)
// {
// var country = new Country
// {
// Id = _countries.Any() ? _countries.Max(c => c.Id) + 1 : 1,
// Name = _countryNames[_random.Next(_countryNames.Length)],
// };
// _countries.Add(country);
// }
// }
// finally
// {
// _semaphore.Release();
// }
//}
}
}
Loading…
Cancel
Save