---
sidebar_position: 5
title: Sous-composant du composant
---

Notre composant va surtout faire appelle à un item, que cela soit pour remplir la grille, afficher les cases de la recette et même le résultat.

Afin de ne pas avoir à répeter du code dans notre composant nous allons donc créer un sous composant qui permettra l'affichage de nos éléments.

Notre composant reste simple mais fait appel au méthode de Drag & Drop.

## Création de la vue de notre composant de base

```cshtml title="Components/CraftingItem.razor"
<div
    class="item"
    ondragover="event.preventDefault();"
    draggable="true"
    @ondragstart="@OnDragStart"
    @ondrop="@OnDrop"
    @ondragenter="@OnDragEnter"
    @ondragleave="@OnDragLeave">

    @if (Item != null)
    {
        @Item.DisplayName
    }
</div>
```

Nous utilisons l'envent handling de Razor concernant les méthodes du Drag & Drop.

## Création du code de notre composant

Le code de notre item reste simple, nous faisons appel à notre parent afin de lui passer les informations d'action ainsi que de Drag & Drop.

```csharp title="Components/CraftingItem.razor.cs"
public partial class CraftingItem
{
	[Parameter]
	public int Index { get; set; }

	[Parameter]
	public Item Item { get; set; }

	[Parameter]
	public bool NoDrop { get; set; }

	[CascadingParameter]
	public Crafting Parent { get; set; }

	internal void OnDragEnter()
	{
		if (NoDrop)
		{
			return;
		}

		Parent.Actions.Add(new CraftingAction { Action = "Drag Enter", Item = this.Item, Index = this.Index });
	}

	internal void OnDragLeave()
	{
		if (NoDrop)
		{
			return;
		}

		Parent.Actions.Add(new CraftingAction { Action = "Drag Leave", Item = this.Item, Index = this.Index });
	}

	internal void OnDrop()
	{
		if (NoDrop)
		{
			return;
		}

		this.Item = Parent.CurrentDragItem;
		Parent.RecipeItems[this.Index] = this.Item;

		Parent.Actions.Add(new CraftingAction { Action = "Drop", Item = this.Item, Index = this.Index });

		// Check recipe
		Parent.CheckRecipe();
	}

	private void OnDragStart()
	{
		Parent.CurrentDragItem = this.Item;

		Parent.Actions.Add(new CraftingAction { Action = "Drag Start", Item = this.Item, Index = this.Index });
	}
}
```

Il est possible de créer aussi des fichiers de style CSS directement pour notre composant, ce fichier sera automatiquement rendu avec notre composant.

```css title="Components/CraftingItem.razor.css"
.item {
    width: 64px;
    height: 64px;
    border: 1px solid;
    overflow: hidden;
}
```

## Notion : Event handling

Spécifiez les gestionnaires d'événements délégués dans le balisage du composant Razor avec la syntaxe Razor `@on{DOM EVENT}="{DELEGATE}"` :
* L'espace réservé `{DOM EVENT}` est un événement DOM (Document Object Model) (par exemple, `click`).
* L'espace réservé `{DELEGATE}` est le gestionnaire d'événement délégué C#.

Pour la gestion des événements :
* Les gestionnaires d'événements délégués asynchrones qui renvoient une tâche sont pris en charge.
* Les gestionnaires d'événements délégués déclenchent automatiquement un rendu d'interface utilisateur, il n'est donc pas nécessaire d'appeler manuellement StateHasChanged.
* Les exceptions sont enregistrées.

Le code suivant :
* Appelle la méthode `UpdateHeading` lorsque le bouton est sélectionné dans l'interface utilisateur.
* Appelle la méthode `CheckChanged` lorsque la case à cocher est modifiée dans l'interface utilisateur.

```cshtml title="Pages/EventHandlerExample1.razor"
@page "/event-handler-example-1"

<h1>@currentHeading</h1>

<p>
    <label>
        New title
        <input @bind="newHeading" />
    </label>
// highlight-next-line
		Update heading
    </button>
</p>

<p>
    <label>
// highlight-next-line
        <input type="checkbox" @onchange="CheckChanged" />
        @checkedMessage
    </label>
</p>

@code {
    private string currentHeading = "Initial heading";
    private string? newHeading;
    private string checkedMessage = "Not changed yet";
	
// highlight-start
    private void UpdateHeading()
    {
        currentHeading = $"{newHeading}!!!";
    }

    private void CheckChanged()
    {
        checkedMessage = $"Last changed at {DateTime.Now}";
    }
// highlight-end
}
```

Dans l'exemple suivant, `UpdateHeading` :
* Est appelé de manière asynchrone lorsque le bouton est sélectionné.
* Attend deux secondes avant de mettre à jour le titre.

```cshtml title="Pages/EventHandlerExample2.razor"
@page "/event-handler-example-2"

<h1>@currentHeading</h1>

<p>
    <label>
        New title
        <input @bind="newHeading" />
    </label>
// highlight-next-line
    <button @onclick="UpdateHeading">
        Update heading
    </button>
</p>

@code {
    private string currentHeading = "Initial heading";
    private string? newHeading;

// highlight-start
    private async Task UpdateHeading()
    {
        await Task.Delay(2000);

        currentHeading = $"{newHeading}!!!";
    }
// highlight-end
}
```

### Arguments d'événement

Pour les événements qui prennent en charge un type d'argument d'événement, la spécification d'un paramètre d'événement dans la définition de méthode d'événement n'est nécessaire que si le type d'événement est utilisé dans la méthode.

Dans l'exemple suivant, `MouseEventArgs` est utilisé dans la méthode `ReportPointerLocation` pour définir le texte du message qui signale les coordonnées de la souris lorsque l'utilisateur sélectionne un bouton dans l'interface utilisateur.

```cshtml title="Pages/EventHandlerExample3.razor"
@page "/event-handler-example-3"

@for (var i = 0; i < 4; i++)
{
    <p>
        <button @onclick="ReportPointerLocation">
            Where's my mouse pointer for this button?
        </button>
    </p>
}

<p>@mousePointerMessage</p>

@code {
    private string? mousePointerMessage;

// highlight-start
    private void ReportPointerLocation(MouseEventArgs e)
    {
        mousePointerMessage = $"Mouse coordinates: {e.ScreenX}:{e.ScreenY}";
    }
// highlight-end
}
```

### EventArgs pris en charge

| Event | Class | Document Object Model (DOM) events |
| ---- | ---- | ---- |
| Clipboard | ClipboardEventArgs | `oncut`, `oncopy`, `onpaste` |
| Drag | DragEventArgs | `ondrag`, `ondragstart`, `ondragenter`, `ondragleave`, `ondragover`, `ondrop`, `ondragend` |
| Error | ErrorEventArgs | `onerror` |
| General | EventArgs | `onactivate`, `onbeforeactivate`, `onbeforedeactivate`, `ondeactivate`, `onfullscreenchange`, `onfullscreenerror`, `onloadeddata`, `onloadedmetadata`, `onpointerlockchange`, `onpointerlockerror`, `onreadystatechange`, `onscroll` |
| Clipboard | EventArgs | `onbeforecut`, `onbeforecopy`, `onbeforepaste` |
| Input | EventArgs | `oninvalid`, `onreset`, `onselect`, `onselectionchange`, `onselectstart`, `onsubmit` |
| Media | EventArgs | `oncanplay`, `oncanplaythrough`, `oncuechange`, `ondurationchange`, `onemptied`, `onended`, `onpause`, `onplay`, `onplaying`, `onratechange`, `onseeked`, `onseeking`, `onstalled`, `onstop`, `onsuspend`, `ontimeupdate`, `ontoggle`, `onvolumechange`, `onwaiting` |
| Focus | FocusEventArgs | `onfocus`, `onblur`, `onfocusin`, `onfocusout` |
| Input | ChangeEventArgs | `onchange`, `oninput` |
| Keyboard | KeyboardEventArgs | `onkeydown`, `onkeypress`, `onkeyup` |
| Mouse | MouseEventArgs | `onclick`, `oncontextmenu`, `ondblclick`, `onmousedown`, `onmouseup`, `onmouseover`, `onmousemove`, `onmouseout` |
| Mouse pointer | PointerEventArgs | `onpointerdown`, `onpointerup`, `onpointercancel`, `onpointermove`, `onpointerover`, `onpointerout`, `onpointerenter`, `onpointerleave`, `ongotpointercapture`, `onlostpointercapture` |
| Mouse wheel | WheelEventArgs | `onwheel`, `onmousewheel` |
| Progress | ProgressEventArgs | `onabort`, `onload`, `onloadend`, `onloadstart`, `onprogress`, `ontimeout` |
| Touch | TouchEventArgs | `ontouchstart`, `ontouchend`, `ontouchmove`, `ontouchenter`, `ontouchleave`, `ontouchcancel` |
