---
sidebar_position: 6
title: Création du formulaire
---

Ouvrez le fichier `Pages/Add.razor` et modifier le fichier suite :

```cshtml title="Pages/Add.razor"
@page "/add"

<h3>Add</h3>

<EditForm Model="@itemModel" OnValidSubmit="@HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <p>
        <label for="display-name">
            Display name:
            <InputText id="display-name" @bind-Value="itemModel.DisplayName" />
        </label>
    </p>
    <p>
        <label for="name">
            Name:
            <InputText id="name" @bind-Value="itemModel.Name" />
        </label>
    </p>
    <p>
        <label for="stack-size">
            Stack size:
            <InputNumber id="stack-size" @bind-Value="itemModel.StackSize" />
        </label>
    </p>
    <p>
        <label for="max-durability">
            Max durability:
            <InputNumber id="max-durability" @bind-Value="itemModel.MaxDurability" />
        </label>
    </p>
    <p>
        Enchant categories:
        <div>
            @foreach (var item in enchantCategories)
            {
                <label>
                    <input type="checkbox" @onchange="@(e => OnEnchantCategoriesChange(item, e.Value))" />@item
                </label>
            }
        </div>
    </p>
    <p>
        Repair with:
        <div>
            @foreach (var item in repairWith)
            {
                <label>
                    <input type="checkbox" @onchange="@(e => OnRepairWithChange(item, e.Value))" />@item
                </label>
            }
        </div>
    </p>
    <p>
        <label>
            Item image:
            <InputFile OnChange="@LoadImage" accept=".png" />
        </label>
    </p>
    <p>
        <label>
            Accept Condition:
            <InputCheckbox @bind-Value="itemModel.AcceptCondition" />
        </label>
    </p>

    <button type="submit">Submit</button>
</EditForm>
```

* Le composant `EditForm` est rendu à l’emplacement où l'élément &lt;EditForm&gt; apparaît.
* Le modèle est créé dans le code du composant et conservé dans un champ privé ( itemModel ). Le champ est assigné à l'attribut `Model` de l'élément &lt;EditForm&gt; .
* Le composant `InputText` ( id="display-name" ) est un composant d’entrée pour la modification des valeurs de chaîne. L'attribut directive `@bind-Value` lie la propriété `itemModel.DisplayName` de modèle à la propriété `Value` du composant `InputText`.
* La méthode `HandleValidSubmit` est assignée à `OnValidSubmit`. Le gestionnaire est appelé si le formulaire réussit la validation.
* Le validateur des annotations de données (`DataAnnotationsValidator`) attache la prise en charge de la validation à l’aide des annotations de données :
	* Si le champ de formulaire &lt;input&gt; n’est pas renseigné lorsque le bouton Submit est sélectionné, une erreur s’affiche dans le résumé des validations (`ValidationSummary`) (« The DisplayName field is required. ») et `HandleValidSubmit` n’est pas appelée.
	* Si le champ de formulaire &lt;input&gt; contient plus de cinquante caractères lorsque le bouton Submit est sélectionné, une erreur s’affiche dans le résumé des validations (« Le nom affiché ne doit pas dépasser 50 caractères. ») et `HandleValidSubmit` n’est pas appelée.
	* Si le champ de formulaire &lt;input&gt; contient une valeur valide lorsque le bouton Submit est sélectionné, `HandleValidSubmit` est appelé.

## Code du formulaire

Ouvrez le fichier `Pages/Add.razor.cs` et modifier le fichier suite :

```csharp title="Pages/Add.razor.cs"
public partial class Add
{
	[Inject]
	public ILocalStorageService LocalStorage { get; set; }

	[Inject]
	public IWebHostEnvironment WebHostEnvironment { get; set; }

	/// <summary>
	/// The default enchant categories.
	/// </summary>
	private List<string> enchantCategories = new List<string>() { "armor", "armor_head", "armor_chest", "weapon", "digger", "breakable", "vanishable" };

	/// <summary>
	/// The default repair with.
	/// </summary>
	private List<string> repairWith = new List<string>() { "oak_planks", "spruce_planks", "birch_planks", "jungle_planks", "acacia_planks", "dark_oak_planks", "crimson_planks", "warped_planks" };

	/// <summary>
	/// The current item model
	/// </summary>
	private ItemModel itemModel = new()
	{
		EnchantCategories = new List<string>(),
		RepairWith = new List<string>()
	};

	private async void HandleValidSubmit()
	{
		// Get the current data
		var currentData = await LocalStorage.GetItemAsync<List<Item>>("data");

		// Simulate the Id
		itemModel.Id = currentData.Max(s => s.Id) + 1;

		// Add the item to the current data
		currentData.Add(new Item
		{
			Id = itemModel.Id,
			DisplayName = itemModel.DisplayName,
			Name = itemModel.Name,
			RepairWith = itemModel.RepairWith,
			EnchantCategories = itemModel.EnchantCategories,
			MaxDurability = itemModel.MaxDurability,
			StackSize = itemModel.StackSize,
			CreatedDate = DateTime.Now
		});

		// Save the image
		var imagePathInfo = new DirectoryInfo($"{WebHostEnvironment.WebRootPath}/images");

		// Check if the folder "images" exist
		if (!imagePathInfo.Exists)
		{
			imagePathInfo.Create();
		}
		
		// Determine the image name
		var fileName = new FileInfo($"{imagePathInfo}/{itemModel.Name}.png");

		// Write the file content
		await File.WriteAllBytesAsync(fileName.FullName, itemModel.ImageContent);
		
		// Save the data
		await LocalStorage.SetItemAsync("data", currentData);
	}

	private async Task LoadImage(InputFileChangeEventArgs e)
	{
		// Set the content of the image to the model
		using (var memoryStream = new MemoryStream())
		{
			await e.File.OpenReadStream().CopyToAsync(memoryStream);
			itemModel.ImageContent = memoryStream.ToArray();
		}
	}

	private void OnEnchantCategoriesChange(string item, object checkedValue)
	{
		if ((bool)checkedValue)
		{
			if (!itemModel.EnchantCategories.Contains(item))
			{
				itemModel.EnchantCategories.Add(item);
			}

			return;
		}

		if (itemModel.EnchantCategories.Contains(item))
		{
			itemModel.EnchantCategories.Remove(item);
		}
	}

	private void OnRepairWithChange(string item, object checkedValue)
	{
		if ((bool)checkedValue)
		{
			if (!itemModel.RepairWith.Contains(item))
			{
				itemModel.RepairWith.Add(item);
			}

			return;
		}

		if (itemModel.RepairWith.Contains(item))
		{
			itemModel.RepairWith.Remove(item);
		}
	}
}
```

Vous pouvez désormais ajouter un nouvel item, si vous retourner sur la liste le votre nouvel élement est présent.

## Notion : Formulaire et validation

### Composants de formulaire intégrés

L'infrastructure Blazor fournit des composants de formulaire intégrés pour recevoir et valider les entrées utilisateur. 
Les entrées sont validées lorsqu’elles sont modifiées et lorsqu’un formulaire est envoyé. 
Les composants d’entrée disponibles sont répertoriés dans le tableau suivant.

| Composant d’entrée | Rendu comme… |
| ----------- | ----------- |
| InputCheckbox | `<input type="checkbox">` |
| InputDate&lt;TValue&gt; | `<input type="date">` |
| InputFile | `<input type="file">` |
| InputNumber&lt;TValue&gt; | `<input type="number">` |
| InputRadio&lt;TValue&gt; | `<input type="radio">` |
| InputRadioGroup&lt;TValue&gt; | Groupe d’enfants InputRadio&lt;TValue&gt; |
| InputSelect&lt;TValue&gt; | `<select>` |
| InputText | `<input>` |
| InputTextArea | `<textarea>` |

Pour plus d’informations sur le InputFile composant, consultez [ASP.NET Core Blazor chargements de fichiers](https://docs.microsoft.com/fr-fr/aspnet/core/blazor/file-uploads).

Tous les composants d’entrée, y compris EditForm , prennent en charge les attributs arbitraires. Tout attribut qui ne correspond pas à un paramètre de composant est ajouté à l’élément HTML rendu.

Les composants d’entrée fournissent le comportement par défaut pour valider quand un champ est modifié, y compris la mise à jour de la classe CSS Field pour refléter l’état du champ comme valide ou non valide. 
Certains composants incluent une logique d’analyse utile. 

Par exemple, InputDate&lt;TValue&gt; et InputNumber&lt;TValue&gt; gèrent correctement les valeurs non analysables en inscrivant des valeurs non analysables en tant qu’erreurs de validation. 
Les types qui peuvent accepter des valeurs NULL prennent également en charge la possibilité de valeur null du champ cible (par exemple, int? pour un entier Nullable).