---
sidebar_position: 6
title: Component code
---

Here is the code of our main component, it is he who will call our basic item and perform a large part of the actions.

## Creation of the view

```cshtml title="Components/Crafting.razor"
<CascadingValue Value="@this">
    <div class="container">
        <div class="row">
            <div class="col-6">
                
                <div>Available items:</div>
                <div>
                    <div class="css-grid">
                        
                        @foreach (var item in Items)
                        {
                            <CraftingItem Item="item" NoDrop="true"/>
                        }
                    </div>
                </div>

            </div>

            <div class="col-6">
                <div>Recipe</div>
                
                <div>
                    
                    <div class="css-recipe">
                        <CraftingItem Index="0"/>
                        <CraftingItem Index="1"/>
                        <CraftingItem Index="2"/>
                        <CraftingItem Index="3"/>
                        <CraftingItem Index="4"/>
                        <CraftingItem Index="5"/>
                        <CraftingItem Index="6"/>
                        <CraftingItem Index="7"/>
                        <CraftingItem Index="8"/>
                    </div>
                </div>
                
                <div>Result</div>
                <div>
                    <CraftingItem Item="RecipeResult"/>
                </div>
            </div>

            <div class="col-12">
                <div>Actions</div>
                <div class="actions" id="actions">

                </div>
            </div>
        </div>
    </div>
</CascadingValue>
```

## Code creation

We use an `ObservableCollection` to allow an action on a change in the list with the `CollectionChanged` event.

```csharp title="Components/Crafting.razor.cs"
public partial class Crafting
{
	private Item _recipeResult;

	public Crafting()
	{
		Actions = new ObservableCollection<CraftingAction>();
		Actions.CollectionChanged += OnActionsCollectionChanged;
		this.RecipeItems = new List<Item> { null, null, null, null, null, null, null, null, null };
	}

	public ObservableCollection<CraftingAction> Actions { get; set; }
	public Item CurrentDragItem { get; set; }

	[Parameter]
	public List<Item> Items { get; set; }

	public List<Item> RecipeItems { get; set; }

	public Item RecipeResult
	{
		get => this._recipeResult;
		set
		{
			if (this._recipeResult == value)
			{
				return;
			}

			this._recipeResult = value;
			this.StateHasChanged();
		}
	}

	[Parameter]
	public List<CraftingRecipe> Recipes { get; set; }

	/// <summary>
	/// Gets or sets the java script runtime.
	/// </summary>
	[Inject]
	internal IJSRuntime JavaScriptRuntime { get; set; }

	public void CheckRecipe()
	{
		RecipeResult = null;

		// Get the current model
		var currentModel = string.Join("|", this.RecipeItems.Select(s => s != null ? s.Name : string.Empty));

		this.Actions.Add(new CraftingAction { Action = $"Items : {currentModel}" });

		foreach (var craftingRecipe in Recipes)
		{
			// Get the recipe model
			var recipeModel = string.Join("|", craftingRecipe.Have.SelectMany(s => s));

			this.Actions.Add(new CraftingAction { Action = $"Recipe model : {recipeModel}" });

			if (currentModel == recipeModel)
			{
				RecipeResult = craftingRecipe.Give;
			}
		}
	}

	private void OnActionsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
	{
		JavaScriptRuntime.InvokeVoidAsync("Crafting.AddActions", e.NewItems);
	}
}
```

As for our element we create a CSS file for our component.

```css title="Components/Crafting.razor.css"
.css-grid {
    grid-template-columns: repeat(4,minmax(0,1fr));
    gap: 10px;
    display: grid;
    width: 286px;
}

.css-recipe {
    grid-template-columns: repeat(3,minmax(0,1fr));
    gap: 10px;
    display: grid;
    width: 212px;
}

.actions {
    border: 1px solid black;
    height: 250px;
    overflow: scroll;
}
```

A JavaScript class is also created to interact with the page.

```js title="Components/Crafting.razor.js"
window.Crafting =
{
    AddActions: function (data) {

        data.forEach(element => {
            var div = document.createElement('div');
            div.innerHTML = 'Action: ' + element.action + ' - Index: ' + element.index;

            if (element.item) {
                div.innerHTML += ' - Item Name: ' + element.item.name;
            }

            document.getElementById('actions').appendChild(div);
        });
    }
}
```


## Concept: CascadingValue & CascadingParameter

In our component we need to know our parent when we are in an item in order to call the `CheckRecipe()` methods as well as to add actions or to know the element we are moving.

We therefore use in the view of our component `Crafting.razor` the following code:

```html title="Crafting.razor"
<CascadingValue Value="@this">
	...
		<CraftingItem Item="item" NoDrop="true"/>
	...
</CascadingValue>
```

This code makes it possible to make our component available in all the sub-components found in the `CascadingValue` tag.

To retrieve our `CascadingValue` we must use in our component a `CascadingParameter` as follows:

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

It would be possible to go through `Parameter` but in case of multiple levels, it would be necessary in each level to add our `Parameter` to nest them:

```cshtml title="Components/MyRootComponent.razor"
@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }

    [Parameter]
    public string Text { get; set; }
}

<div style="border: 1px solid black; padding: 10px;">
    <strong>MyRootComponent - @Text</strong>
    <div>
        @ChildContent
    </div>
</div>
```

```cshtml title="Components/MyFirstChildComponent.razor"
@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }

    [Parameter]
    public MyRootComponent RootComponent { get; set; }
}

<div style="border: 1px solid black; padding: 10px;">
    <strong>MyFirstChildComponent - @RootComponent.Text</strong>
    <div>
        @ChildContent
    </div>
</div>
```

```cshtml title="Components/MySecondChildComponent.razor"
@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }

    [Parameter]
    public MyRootComponent RootComponent { get; set; }
}

<div style="border: 1px solid black; padding: 10px;">
    <strong>MySecondChildComponent - @RootComponent.Text</strong>
    <div>
        @ChildContent
    </div>
</div>
```

```cshtml title="Pages/Index.razor"
@code
{
    MyRootComponent MyRootComponent;
}

<MyRootComponent @ref="MyRootComponent" Text="RootComponentText">
    <MyFirstChildComponent RootComponent="@MyRootComponent">
        <MySecondChildComponent RootComponent="@MyRootComponent">
            <div>MySecondChildComponent - Content</div>
        </MySecondChildComponent>
    </MyFirstChildComponent>
</MyRootComponent>
```

This also forces the developer to declare the component's usage variable each time it is used, as well as having to specify an attribute with its value.

Whereas with `CascadingValue` & `CascadingParameter` the code becomes simpler:

```cshtml title="Components/MyRootComponent.razor"
@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }

    [Parameter]
    public string Text { get; set; }
}

<div style="border: 1px solid black; padding: 10px;">
    <strong>MyRootComponent - @Text</strong>
    <div>
        <CascadingValue Value="@this">
            @ChildContent
        </CascadingValue>
    </div>
</div>
```

```cshtml title="Components/MyFirstChildComponent.razor"
@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }

    [CascadingParameter]
    public MyRootComponent RootComponent { get; set; }
}

<div style="border: 1px solid black; padding: 10px;">
    <strong>MyFirstChildComponent - @RootComponent.Text</strong>
    <div>
        @ChildContent
    </div>
</div>
```

```cshtml title="Components/MySecondChildComponent.razor"
@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }

    [CascadingParameter]
    public MyRootComponent RootComponent { get; set; }
}

<div style="border: 1px solid black; padding: 10px;">
    <strong>MySecondChildComponent - @RootComponent.Text</strong>
    <div>
        @ChildContent
    </div>
</div>
```

```cshtml title="Pages/Index.razor"
<MyRootComponent Text="RootComponentText">
    <MyFirstChildComponent>
        <MySecondChildComponent>
            <div>MySecondChildComponent - Content</div>
        </MySecondChildComponent>
    </MyFirstChildComponent>
</MyRootComponent>
```

## Concept: IJSRuntime

To call JS from .net, inject the `IJSRuntime` abstraction and call one of the following methods:

* IJSRuntime.InvokeAsync
* JSRuntimeExtensions.InvokeAsync
* JSRuntimeExtensions.InvokeVoidAsync

For previous .NET methods that call JS functions:

* The function identifier ( `String` ) is relative to the global scope ( `window` ). To call `window.someScope.someFunction`, the identifier is `someScope.someFunction`. There is no need to register the function before it is called.
* Pass any number of on-Serializable JS arguments in `Object[]` to a JS function.
* The cancellation token ( `CancellationToken` ) propagates a notification that operations should be canceled.
* `TimeSpan` represents a time limit for a JS operation.
* The `TValue` return type must also be serializable. `TValue` should be the .NET type that best matches the JS returned type.
* `JS A Promise` is returned for `InvokeAsync` methods. `InvokeAsync` unwraps `Promise` and returns the value expected by `Promise`.

For apps that have Blazor Server pre-render enabled, invoking JS is not possible during the initial pre-render. Interop JS calls should be deferred until the connection with the browser is established.

The following example is based on `TextDecoder`, a JS-based decoder.
The sample demonstrates how to call a JS function from a C# method that offloads a specification from developer code to an existing JS API.
The JS function accepts a byte array from a C# method, decodes the array, and returns the text to the component for display.

Add the following JS code inside the closing `</body>` tag in the `wwwroot/index.html` file:

```html
<script>
  window.convertArray = (win1251Array) => {
    var win1251decoder = new TextDecoder('windows-1251');
    var bytes = new Uint8Array(win1251Array);
    var decodedArray = win1251decoder.decode(bytes);
    console.log(decodedArray);
    return decodedArray;
  };
</script>
```

The following `CallJsExample1` component:

* Calls the JS function `convertArray` with `InvokeAsync` when selecting a button ( `Convert Array` ).
* Once the JS function is called, the passed array is converted to a string. The string is returned to the component for display ( `text` ).

```cshtml title="Pages/CallJsExample1.razor"
@page "/call-js-example-1"
@inject IJSRuntime JS

<h1>Call JS <code>convertArray</code> Function</h1>

<p>
    <button @onclick="ConvertArray">Convert Array</button>
</p>

<p>
    @text
</p>

<p>
    <a href="https://www.imdb.com/title/tt0379786/" target="_blank">Serenity</a><br>
    <a href="https://www.imdb.com/name/nm0472710/" target="_blank">David Krumholtz on IMDB</a>
</p>

@code {
    private MarkupString text;

    private uint[] quoteArray = 
        new uint[]
        {
            60, 101, 109, 62, 67, 97, 110, 39, 116, 32, 115, 116, 111, 112, 32,
            116, 104, 101, 32, 115, 105, 103, 110, 97, 108, 44, 32, 77, 97,
            108, 46, 60, 47, 101, 109, 62, 32, 45, 32, 77, 114, 46, 32, 85, 110,
            105, 118, 101, 114, 115, 101, 10, 10,
        };

    private async Task ConvertArray()
    {
        text = new(await JS.InvokeAsync<string>("convertArray", quoteArray));
    }
}
```

### Call JavaScript functions without reading a returned value ( `InvokeVoidAsync` )

Use `InvokeVoidAsync` in the following cases:

* .NET is not required to read the result of a JS call.
* JS functions return `void (0)`/`void 0` or undefined.

Inside the closing `</body>` tag of `wwwroot/index.html`, provide a JS function `displayTickerAlert1`. The function is called with `InvokeVoidAsync` and does not return a value:

```html
<script>
  window.displayTickerAlert1 = (symbol, price) => {
    alert(`${symbol}: $${price}!`);
  };
</script>
```

`TickerChanged` calls the `handleTickerChanged1` method in the following component `CallJsExample2`.

```cshtml
@page "/call-js-example-2"
@inject IJSRuntime JS

<h1>Call JS Example 2</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@code {
    private Random r = new();
    private string? stockSymbol;
    private decimal price;

    private async Task SetStock()
    {
        stockSymbol = 
            $"{(char)('A' + r.Next(0, 26))}{(char)('A' + r.Next(0, 26))}";
        price = r.Next(1, 101);
        await JS.InvokeVoidAsync("displayTickerAlert1", stockSymbol, price);
    }
}
```

### Calling JavaScript functions and reading a returned value ( `InvokeAsync` )

Use `InvokeAsync` when .net needs to read the result of a JS call.

Inside the closing `</body>` tag of `wwwroot/index.html`, provide a JS function `displayTickerAlert2`. The following example returns a string to be displayed by the caller:

```html
<script>
  window.displayTickerAlert2 = (symbol, price) => {
    if (price < 20) {
      alert(`${symbol}: $${price}!`);
      return "User alerted in the browser.";
    } else {
      return "User NOT alerted.";
    }
  };
</script>
```

`TickerChanged` calls the `handleTickerChanged2` method and displays the returned string in the following component `CallJsExample3`.

```cshtml title="Pages/CallJsExample3.razor"
@page "/call-js-example-3"
@inject IJSRuntime JS

<h1>Call JS Example 3</h1>

<p>
    <button @onclick="SetStock">Set Stock</button>
</p>

@if (stockSymbol is not null)
{
    <p>@stockSymbol price: @price.ToString("c")</p>
}

@if (result is not null)
{
    <p>@result</p>
}

@code {
    private Random r = new();
    private string? stockSymbol;
    private decimal price;
    private string? result;

    private async Task SetStock()
    {
        stockSymbol = 
            $"{(char)('A' + r.Next(0, 26))}{(char)('A' + r.Next(0, 26))}";
        price = r.Next(1, 101);
        var interopResult = 
            await JS.InvokeAsync<string>("displayTickerAlert2", stockSymbol, price);
        result = $"Result of TickerChanged call for {stockSymbol} at " +
            $"{price.ToString("c")}: {interopResult}";
    }
}
```
