Sfruttare le potenzialità dei moduli Blazor

Completato

Gli utenti immettono i dati usando i moduli. In un'app Web classica si crea un modulo usando l'elemento <form> e si abilita l'utente all'invio di dati tramite elementi <input>. Quando l'utente invia il modulo, l'input può essere convalidato. Se la convalida ha esito positivo, è possibile eseguire le azioni appropriate, ad esempio usando le informazioni fornite per aggiungere una nuova voce a un database o per aggiornare un record.

Le strutture e <input> gli <form> elementi forniscono sono semplici, ma relativamente primitivi. Blazor estende le funzionalità dei moduli con il componente <EditForm>. Blazor fornisce inoltre una serie di elementi di input specializzati che è possibile usare per formattare e convalidare i dati immessi dall'utente.

In questa unità si apprenderà come usare l'elemento <EditForm> e gli elementi input per compilare moduli funzionali. Verrà anche illustrato come eseguire il data binding con un modulo.

Che cos'è un Modulo di modifica?

Un EditForm è un componente Blazor che svolge il ruolo di un modulo HTML in una pagina Blazor. Le differenze principali tra un EditForm e un modulo HTML sono:

  • Data binding: è possibile associare un oggetto a un controllo EditForm. L'elemento EditForm funge da visualizzazione dell'oggetto per l'immissione e la visualizzazione dei dati.
  • Convalida: EditForm offre funzionalità di convalida estese ed estendibili. È possibile aggiungere attributi agli elementi in un EditForm che specificano le regole di convalida. L'elemento EditForm applicherà automaticamente queste regole. Questa funzionalità è descritta in un'unità successiva in questo modulo.
  • Invio di moduli: un modulo HTML invia una richiesta di post a un gestore di moduli quando viene inviato. Si prevede che questo gestore del modulo esegua il processo di invio e quindi visualizzi tutti i risultati. Un EditForm segue il modello di evento Blazor. Specificare un gestore eventi C# che acquisisce l'evento OnSubmit. Il gestore eventi esegue la logica di invio.
  • Elementi di input: un modulo HTML usa un <input> controllo per raccogliere l'input dell'utente e un submit pulsante per pubblicare il modulo per l'elaborazione. Un EditForm può usare questi stessi elementi, ma Blazor offre una libreria di componenti di input che includono altre funzionalità, ad esempio la convalida predefinita e il data binding.

Creare un EditForm con data binding

L'elemento <EditForm> supporta il data binding con il parametro Model. Specificare un oggetto come argomento per questo parametro. Gli elementi di input nell'oggetto EditForm possono essere associati a proprietà e campi esposti dal modello usando il parametro @bind-Value. L'esempio seguente si basa sulla WeatherForecast classe creata dal modello predefinito App Server Blazor. La classe ha questo aspetto:

public class WeatherForecast
{
    public DateTime Date { get; set; }

    public int TemperatureC { get; set; }

    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

    public string Summary { get; set; }
}

Il modello per EditForm è un'istanza della classe WeatherForecast archiviata nella variabile @currentForecast e gli elementi di input sono associati ai campi nella classe:

@page "/fetchdata"

@using WebApplication.Data
@inject WeatherForecastService ForecastService

<h1>Weather forecast</h1>

<input type="number" width="2" min="0" max="@upperIndex" @onchange="ChangeForecast" value="@index"/>

<EditForm Model=@currentForecast>
    <InputDate @bind-Value=currentForecast.Date></InputDate>
    <InputNumber @bind-Value=currentForecast.TemperatureC></InputNumber>
    <InputText @bind-Value=currentForecast.Summary></InputText>
</EditForm>

@code {
    private WeatherForecast[] forecasts;
    private WeatherForecast currentForecast;
    private int index = 0;
    private int upperIndex = 0;

    protected override async Task OnInitializedAsync()
    {
        forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
        currentForecast = forecasts[index];
        upperIndex = forecasts.Count() - 1;
    }

    private async Task ChangeForecast(ChangeEventArgs e)
    {
        index = int.Parse(e.Value as string);
        if (index <= upperIndex && index >= 0)
        {
            currentForecast = forecasts[index];
        }
    }
}

In questo esempio l'evento OnInitialized popola una matrice di oggetti WeatherForecast usando un servizio esterno. La variabile currentForecast è impostata sul primo elemento della matrice. Si tratta dell'oggetto visualizzato da EditForm. L'utente può scorrere in sequenza la matrice usando il campo di input numerico sopra all'elemento EditForm nella pagina. Il valore di questo campo viene usato come indice della matrice e la currentForecast variabile viene impostata sull'oggetto trovato in tale indice usando il ChangeForecast metodo .

L'immagine seguente mostra un esempio della pagina in esecuzione:

Screenshot of the EditForm containing controls bound to a WeatherForecast object.

Importante

Il componente EditForm implementa il data binding bidirezionale. Nel modulo vengono visualizzati i valori recuperati dal modello, ma l'utente può aggiornare questi valori nel modulo e verrà eseguito il push nel modello.

Informazioni sui controlli di input Blazor

L'elemento HTML <form> supporta l'elemento <input> per consentire all'utente di immettere i dati. L'elemento <input> include una proprietà type che ne specifica il tipo e la modalità di visualizzazione, ad esempio numero, casella di testo, pulsante di opzione, casella di controllo, pulsante di controllo e così via.

Blazor include un set di componenti progettati per funzionare in modo specifico con l'elemento <EditForm> e supportare il data binding tra le altre funzionalità. Nella tabella seguente sono elencati questi componenti. Quando Blazor esegue il rendering di una pagina contenente questi componenti, essi vengono convertiti negli elementi HTML <input> corrispondenti elencati nella tabella. Alcuni dei componenti Blazor sono generici. Il parametro di tipo viene accertato dal runtime Blazor a seconda del tipo di dati associati all'elemento:

Componente di input Sottoposto a rendering come (HTML)
InputCheckbox <input type="checkbox">
InputDate<TValue> <input type="date">
InputFile <input type="file">
InputNumber<TValue> <input type="number">
InputRadio<TValue> <input type="radio">
InputRadioGroup<TValue> Gruppo di pulsanti di opzione figlio
InputSelect<TValue> <select>
InputText <input>
InputTextArea <textarea>

Ognuno di questi elementi ha attributi riconosciuti da Blazor, ad esempio DisplayName, che viene usato per associare un elemento di input a un'etichetta e @ref, che è possibile usare per salvare un riferimento a un campo in una variabile C#. Tutti gli attributi non Blazor non riconosciuti vengono passati senza modifiche al renderer HTML. Ciò significa che è possibile usare gli attributi degli elementi di input HTML. Ad esempio, è possibile aggiungere gli minattributi , maxe step a un InputNumber componente e funzioneranno correttamente come parte dell'elemento di cui viene eseguito il <input type="number"> rendering. Nell'esempio precedente è possibile specificare il campo di input TemperatureC come:

<EditForm Model=@currentForecast>
    <InputNumber @bind-Value=currentForecast.TemperatureC width="5" min="-100" step="5"></InputNumber>
</EditForm>

Nell'esempio successivo viene illustrato come usare i componenti InputRadioGroup<TValue> e InputRadio<TValue>. In genere si usa un gruppo di pulsanti di opzione per presentare una serie di pulsanti di opzione. Ogni pulsante consente all'utente di selezionare un valore da un determinato set. Un EditForm può contenere più componenti RadioButtonGroup<TValue> e ogni gruppo può essere associato a un campo nel modello per l'elemento EditForm. L'esempio seguente presenta i dettagli di un'app di abbigliamento-store. Il modulo visualizza i dati per le magliette. La classe del modello Shirt ha questo aspetto:

public enum ShirtColor
{
    Red, Blue, Yellow, Green, Black, White
};

public enum ShirtSize
{
    Small, Medium, Large, ExtraLarge
};

public class Shirt
{
    public ShirtColor Color { get; set; }
    public ShirtSize Size { get; set; }
    public decimal Price;
}

Si noti che il colore e le dimensioni della maglietta vengono specificati come enumerazioni. Nella pagina Razor seguente il codice crea un Shirt oggetto da usare come dati di test. L'elemento <EditForm> è associato a questo oggetto. Il modulo visualizza le dimensioni, il colore e il prezzo della T-shirt. Il primo elemento <InputRadioGroup> è collegato alla proprietà Size. Il ciclo foreach esegue l'iterazione dei valori possibili nell'enumerazione e crea un elemento <InputRadio> per ognuno di essi. L'attributo Name dell'elemento <InputRadio> deve corrispondere a quello dell'elemento <InputRadioGroup>. Il renderer HTML usa questo attributo per collegare il gruppo e i pulsanti di opzione. Il secondo elemento <InputRadioGroup> è collegato alla proprietà Color e usa la stessa tecnica per generare pulsanti di opzione per ogni taglia. L'elemento finale visualizza il prezzo usando un elemento <InputNumber>. Questo elemento applica gli attributi max, min e step disponibili con l'elemento HTML <input>. In questo esempio vengono usati elementi <label> per visualizzare il nome del valore associato a ogni componente.

<EditForm Model="@shirt">
    <label>
        <h3>Size</h3>
        <InputRadioGroup Name="size" @bind-Value=shirt.Size>
            @foreach(var shirtSize in Enum.GetValues(typeof(ShirtSize)))
            {
                <label>@shirtSize:
                    <InputRadio Name="size" Value="@shirtSize"></InputRadio>
                </label>
                <br />
            }
        </InputRadioGroup>
    </label>
    <p></p>
    <label>
        <h3>Color</h3>
        <InputRadioGroup Name="color" @bind-Value=shirt.Color>
            @foreach(var shirtColor in Enum.GetValues(typeof(ShirtColor)))
            {
                <label>@shirtColor:
                    <InputRadio Name="color" Value="@shirtColor"></InputRadio>
                </label>
                <br />
            }
        </InputRadioGroup>
    </label>
    <p></p>
    <label>
        <h3>Price</h3>
        <InputNumber @bind-Value=shirt.Price min="0" max="100" step="0.01"></InputNumber>
    </label>
</EditForm>

@code {
    private Shirt shirt = new Shirt
    {
        Size = ShirtSize.Large,
        Color = ShirtColor.Blue,
        Price = 9.99M
    };
}

Quando si esegue il modulo, avrà questo aspetto:

Screenshot of the EditForm showing the radio button groups for T-Shirt size and color.

Gestire gli invii del modulo

Si è visto che è possibile usare un EditForm oggetto per modificare i dati nel modello sottostante. Al termine delle modifiche, è possibile inviare il modulo per convalidare i dati nel server e salvare le modifiche. Blazor supporta due tipi di convalida: dichiarativa e programmatica. Le regole di convalida dichiarativa operano sul client nel browser. Sono utili per eseguire la convalida lato client di base prima che i dati vengano trasmessi al server. La convalida lato server è utile per la gestione di scenari complessi che non sono disponibili con la convalida dichiarativa, ad esempio il controllo incrociato dei dati in un campo rispetto ai dati di altre origini. Un'applicazione reale deve usare una combinazione di convalida lato client e lato server. La convalida lato client intercetta gli errori di base degli input utente e impedisce molti casi di dati non validi inviati al server per l'elaborazione. La convalida lato server garantisce che una richiesta di salvataggio dei dati da parte dell'utente non tenti di ignorare la convalida dei dati e archivi dati incompleti o danneggiati.

Nota

È anche possibile intercettare eventi JavaScript come onchange e oninput e gli eventi Blazor @onchange e @oninput equivalenti per molti controlli in un EditForm. È possibile usare questi eventi per esaminare e convalidare i dati a livello di codice, campo per campo, prima che l'utente invii il modulo. Questo approccio non è tuttavia consigliato. La ricezione di messaggi di convalida ogni volta che viene immessa una sequenza di tasti o una tabulazione tra i campi può essere frustrante per l'utente. Salvare la convalida per quando l'utente ha completato l'input.

Un EditForm ha tre eventi che vengono eseguiti all'invio:

  • OnValidSubmit: questo evento viene attivato se i campi di input superano correttamente le regole di convalida definite dai relativi attributi di convalida.
  • OnInvalidSubmit: questo evento viene attivato se uno dei campi di input nel modulo non riesce la convalida definita dai relativi attributi di convalida.
  • OnSubmit: questo evento si verifica quando viene inviato EditForm indipendentemente dal fatto che tutti i campi di input siano validi o meno.

Gli eventi OnValidSubmit e OnInvalidSubmit sono utili per un EditForm che implementa la convalida di base a livello del singolo campo di input. Se sono presenti requisiti di convalida più complessi, ad esempio il controllo incrociato di un campo di input rispetto a un altro per garantire una combinazione valida di valori, è consigliabile usare l'evento OnSubmit. Un EditForm oggetto può gestire la OnValidSubmit coppia di eventi e OnInvalidSubmit o l'evento OnSubmit , ma non tutti e tre. Per attivare l'invio, aggiungere un pulsante Submit all'elemento EditForm. Quando l'utente seleziona questo pulsante, vengono attivati gli eventi di invio specificati dall'elemento EditForm.

Nota

Il processo di compilazione e distribuzione non verifica la presenza di una combinazione non valida di eventi di invio, ma una selezione non valida genererà un errore in fase di esecuzione. Ad esempio, se si tenta di usare OnValidSubmit con OnSubmit, l'applicazione genererà l'eccezione di runtime seguente:

Error: System.InvalidOperationException: When supplying an OnSubmit parameter to EditForm, do not also supply OnValidSubmit or OnInvalidSubmit.

L'elemento EditForm tiene traccia dello stato dell'oggetto corrente che funge da modello, inclusi i campi modificati e i relativi valori correnti, tramite un oggetto EditContext. Negli eventi di invio questo oggetto EditContext viene passato come parametro. Un gestore eventi può usare il campo Model in questo oggetto per recuperare l'input dell'utente.

Nell'esempio seguente viene illustrato l'oggetto EditForm dell'esempio precedente con un pulsante di invio. L'elemento EditForm acquisisce l'evento OnSubmit per convalidare le modifiche apportate a un oggetto T-shirt. In questo esempio sono consentite solo alcune combinazioni di valori:

  • Le T-shirt rosse non sono disponibili nella taglia Extra Large
  • Le T-shirt blu non sono disponibili nelle taglie Small o Medium
  • Le magliette bianche hanno un prezzo massimo di $ 50.

Se viene rilevata una combinazione non valida, nel campo Message del modulo viene visualizzato il motivo dell'errore di convalida. Se i campi sono validi, i dati vengono elaborati e salvati (la logica per questo processo non viene visualizzata).

<EditForm Model="@shirt" OnSubmit="ValidateData">
    <!-- Omitted for brevity -->
    <input type="submit" class="btn btn-primary" value="Save"/>
    <p></p>
    <div>@Message</div>
</EditForm>

@code {
    private string Message = String.Empty;

    // Omitted for brevity

    private async Task ValidateData(EditContext editContext)
    {
        if (editContext.Model is not Shirt shirt)
        {
            Message = "T-Shirt object is invalid";
            return;
        }

        if (shirt is { Color: ShirtColor.Red, Size: ShirtSize.ExtraLarge })
        {
            Message = "Red T-Shirts not available in Extra Large size";
            return;
        }

        if (shirt is { Color: ShirtColor.Blue, Size: <= ShirtSize.Medium)
        {
            Message = "Blue T-Shirts not available in Small or Medium sizes";
            return;
        }

        if (shirt is { Color: ShirtColor.White, Price: > 50 })
        {
            Message = "White T-Shirts must be priced at 50 or lower";
            return;
        }

        // Data is valid
        // Save the data
        Message = "Changes saved";
    }
}

L'immagine seguente mostra i risultati se l'utente tenta di fornire dati non validi:

Screenshot of the T-shirt form showing a validation error after it has been submitted.

Verificare le conoscenze

1.

Quale evento viene generato quando viene inviato un EditForm con elementi che non hanno superato la convalida?

2.

Un EditForm presenta le funzionalità seguenti tranne: