Avancée jusqu’à l’api mais problème sur la partie using component

javascript_error
Thomas Chazot 2 years ago
parent 53d57c982b
commit b1cc8d178c

@ -1,4 +1,5 @@
<Router AppAssembly="@typeof(Program).Assembly"> <CascadingBlazoredModal>
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData"> <Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /> <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found> </Found>
@ -6,3 +7,4 @@
<p>Sorry, there's nothing at this address.</p> <p>Sorry, there's nothing at this address.</p>
</NotFound> </NotFound>
</Router> </Router>
</CascadingBlazoredModal>

@ -11,13 +11,38 @@
<PackageReference Include="Blazorise.DataGrid" Version="1.1.2" /> <PackageReference Include="Blazorise.DataGrid" Version="1.1.2" />
<PackageReference Include="Blazorise.Icons.FontAwesome" Version="1.1.2" /> <PackageReference Include="Blazorise.Icons.FontAwesome" Version="1.1.2" />
<PackageReference Include="Blazored.LocalStorage" Version="4.3.0" /> <PackageReference Include="Blazored.LocalStorage" Version="4.3.0" />
<PackageReference Include="Blazored.Modal" Version="7.1.0" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="7.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Remove="Blazored.LocalStorage" /> <None Remove="Blazored.LocalStorage" />
<None Remove="Services\" /> <None Remove="Services\" />
<None Remove="Factories\" />
<None Remove="Blazored.Modal" />
<None Remove="Modals\" />
<None Remove="Microsoft.Extensions.Localization" />
<None Remove="Controllers\" />
<None Remove="Resources\" />
<None Remove="Components\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Services\" /> <Folder Include="Services\" />
<Folder Include="Factories\" />
<Folder Include="Modals\" />
<Folder Include="Controllers\" />
<Folder Include="Resources\" />
<Folder Include="Components\" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Resources\Pages.List.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Pages.List.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Update="Resources\Pages.List.Designer.cs">
<DependentUpon>Pages.List.resx</DependentUpon>
</Compile>
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -0,0 +1,9 @@
<h3>Card</h3>
@typeparam TItem
<div class="card text-center">
@CardHeader(Item)
@CardBody(Item)
@CardFooter
</div>

@ -0,0 +1,21 @@
using System;
using Microsoft.AspNetCore.Components;
namespace BlazorApp.Components
{
public partial class Card<TItem>
{
[Parameter]
public RenderFragment<TItem> CardBody { get; set; }
[Parameter]
public RenderFragment CardFooter { get; set; }
[Parameter]
public RenderFragment<TItem> CardHeader { get; set; }
[Parameter]
public TItem Item { get; set; }
}
}

@ -0,0 +1,54 @@

<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>

@ -0,0 +1,82 @@
using System;
using BlazorApp.Models;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
namespace BlazorApp.Components
{
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);
}
}
}

@ -0,0 +1,19 @@
.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;
}

@ -0,0 +1,20 @@
<script>
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);
});
}
}
</script>

@ -0,0 +1,13 @@
using System;
using BlazorApp.Models;
namespace BlazorApp.Components
{
public class CraftingAction
{
public string Action { get; set; }
public int Index { get; set; }
public Item Item { get; set; }
}
}

@ -0,0 +1,13 @@
<div class="item"
ondragover="event.preventDefault();"
draggable="true"
@ondragstart="@OnDragStart"
@ondrop="@OnDrop"
@ondragenter="@OnDragEnter"
@ondragleave="@OnDragLeave">
@if (Item != null)
{
@Item.DisplayName
}
</div>

@ -0,0 +1,68 @@
using System;
using BlazorApp.Models;
using Blazorise;
using Microsoft.AspNetCore.Components;
namespace BlazorApp.Components
{
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 });
}
}
}

@ -0,0 +1,6 @@
.item {
width: 64px;
height: 64px;
border: 1px solid;
overflow: hidden;
}

@ -0,0 +1,12 @@
using System;
using BlazorApp.Models;
namespace BlazorApp.Components
{
public class CraftingRecipe
{
public Item Give { get; set; }
public List<List<string>> Have { get; set; }
}
}

@ -0,0 +1,14 @@
@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>

@ -0,0 +1,16 @@
@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>

@ -0,0 +1,14 @@
@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>

@ -0,0 +1,11 @@
@typeparam TItem
<div>
@if ((Items?.Count ?? 0) != 0)
{
@foreach (var item in Items)
{
@ShowTemplate(item);
}
}
</div>

@ -0,0 +1,15 @@
using System;
using Microsoft.AspNetCore.Components;
namespace BlazorApp.Components
{
public partial class ShowItems<TItem>
{
[Parameter]
public List<TItem> Items { get; set; }
[Parameter]
public RenderFragment<TItem> ShowTemplate { get; set; }
}
}

@ -0,0 +1,7 @@
<h3>TestRenderFragment</h3>
@code {
[Parameter]
public RenderFragment ChildContent { get; set; }
}

@ -0,0 +1,36 @@
using System;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
namespace BlazorApp.Controllers
{
/// <summary>
/// The culture controller.
/// </summary>
[Route("[controller]/[action]")]
public class CultureController : Controller
{
/// <summary>
/// Sets the culture.
/// </summary>
/// <param name="culture">The culture.</param>
/// <param name="redirectUri">The redirect URI.</param>
/// <returns>
/// The action result.
/// </returns>
public IActionResult SetCulture(string culture, string redirectUri)
{
if (culture != null)
{
// Define a cookie with the selected culture
this.HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(
new RequestCulture(culture)));
}
return this.LocalRedirect(redirectUri);
}
}
}

@ -0,0 +1,53 @@
using System;
using BlazorApp.Models;
namespace BlazorApp.Factories
{
public static class ItemFactory
{
public static ItemModel ToModel(Item item, byte[] imageContent)
{
return new ItemModel
{
Id = item.Id,
DisplayName = item.DisplayName,
Name = item.Name,
RepairWith = item.RepairWith,
EnchantCategories = item.EnchantCategories,
MaxDurability = item.MaxDurability,
StackSize = item.StackSize,
ImageContent = imageContent,
ImageBase64 = string.IsNullOrWhiteSpace(item.ImageBase64) ? Convert.ToBase64String(imageContent) : item.ImageBase64
};
}
public static Item Create(ItemModel model)
{
return new Item
{
Id = model.Id,
DisplayName = model.DisplayName,
Name = model.Name,
RepairWith = model.RepairWith,
EnchantCategories = model.EnchantCategories,
MaxDurability = model.MaxDurability,
StackSize = model.StackSize,
CreatedDate = DateTime.Now
};
}
public static void Update(Item item, ItemModel model)
{
item.DisplayName = model.DisplayName;
item.Name = model.Name;
item.RepairWith = model.RepairWith;
item.EnchantCategories = model.EnchantCategories;
item.MaxDurability = model.MaxDurability;
item.StackSize = model.StackSize;
item.UpdatedDate = DateTime.Now;
}
}
}

@ -0,0 +1,10 @@
<div class="simple-form">
<p>
Are you sure you want to delete @item.DisplayName ?
</p>
<button @onclick="ConfirmDelete" class="btn btn-primary">Delete</button>
<button @onclick="Cancel" class="btn btn-secondary">Cancel</button>
</div>

@ -0,0 +1,40 @@
using System;
using BlazorApp.Models;
using BlazorApp.Services;
using Blazored.Modal;
using Blazored.Modal.Services;
using Microsoft.AspNetCore.Components;
namespace BlazorApp.Modals
{
public partial class DeleteConfirmation
{
[CascadingParameter]
public BlazoredModalInstance ModalInstance { get; set; }
[Inject]
public IDataService DataService { get; set; }
[Parameter]
public int Id { get; set; }
private Item item = new Item();
protected override async Task OnInitializedAsync()
{
// Get the item
item = await DataService.GetById(Id);
}
void ConfirmDelete()
{
ModalInstance.CloseAsync(ModalResult.Ok(true));
}
void Cancel()
{
ModalInstance.CancelAsync();
}
}
}

@ -0,0 +1,11 @@
using System;
namespace BlazorApp.Models
{
public class Cake
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Cost { get; set; }
}
}

@ -11,5 +11,6 @@
public List<string> RepairWith { get; set; } public List<string> RepairWith { get; set; }
public DateTime CreatedDate { get; set; } public DateTime CreatedDate { get; set; }
public DateTime? UpdatedDate { get; set; } public DateTime? UpdatedDate { get; set; }
public string ImageBase64 { get; set; }
} }
} }

@ -34,6 +34,8 @@ namespace BlazorApp.Models
[Required(ErrorMessage = "The image of the item is mandatory!")] [Required(ErrorMessage = "The image of the item is mandatory!")]
public byte[] ImageContent { get; set; } public byte[] ImageContent { get; set; }
public string ImageBase64 { get; set; }
} }
} }

@ -2,4 +2,81 @@
<h3>Edit</h3> <h3>Edit</h3>
<div>My paremeter: @Id</div> <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))" checked="@(itemModel.EnchantCategories.Contains(item) ? "checked" : null)" />@item
</label>
}
</div>
</p>
<p>
Repair with:
<div>
@foreach (var item in repairWith)
{
<label>
<input type="checkbox" @onchange="@(e => OnRepairWithChange(item, e.Value))" checked="@(itemModel.RepairWith.Contains(item) ? "checked" : null)" />@item
</label>
}
</div>
</p>
<p>
<label>
Current Item image:
@if (File.Exists($"{WebHostEnvironment.WebRootPath}/images/{itemModel.Name}.png"))
{
<img src="images/@(itemModel.Name).png" class="img-thumbnail" title="@itemModel.DisplayName" alt="@itemModel.DisplayName" style="max-width: 150px" />
}
else
{
<img src="images/default.png" class="img-thumbnail" title="@itemModel.DisplayName" alt="@itemModel.DisplayName" style="max-width: 150px" />
}
</label>
</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>

@ -1,5 +1,9 @@
using System; using System;
using BlazorApp.Factories;
using BlazorApp.Models;
using BlazorApp.Services;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
namespace BlazorApp.Pages namespace BlazorApp.Pages
{ {
@ -8,6 +12,101 @@ namespace BlazorApp.Pages
[Parameter] [Parameter]
public int Id { get; set; } public int Id { 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 current item model
/// </summary>
private ItemModel itemModel = new()
{
EnchantCategories = new List<string>(),
RepairWith = new List<string>()
};
/// <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" };
[Inject]
public IDataService DataService { get; set; }
[Inject]
public NavigationManager NavigationManager { get; set; }
[Inject]
public IWebHostEnvironment WebHostEnvironment { get; set; }
protected override async Task OnInitializedAsync()
{
var item = await DataService.GetById(Id);
var fileContent = await File.ReadAllBytesAsync($"{WebHostEnvironment.WebRootPath}/images/default.png");
if (File.Exists($"{WebHostEnvironment.WebRootPath}/images/{itemModel.Name}.png"))
{
fileContent = await File.ReadAllBytesAsync($"{WebHostEnvironment.WebRootPath}/images/{item.Name}.png");
}
// Set the model with the item
itemModel = ItemFactory.ToModel(item, fileContent);
}
private async void HandleValidSubmit()
{
await DataService.Update(Id, itemModel);
NavigationManager.NavigateTo("list");
}
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);
}
}
} }
} }

@ -1,9 +1,48 @@
@page "/" @page "/"
@using System.Globalization
@using BlazorApp.Components
<PageTitle>Index</PageTitle> <PageTitle>Index</PageTitle>
<h1>Hello, world!</h1> <h1>Hello, world!</h1>
Welcome to your new app. <!--
<ShowItems Items="Cakes">
<ShowTemplate Context="CakeContext">
<div class="card text-center">
<div class="card-header">
Cake Token Id - @CakeContext.Id
</div>
<div class="card-body">
<h5 class="card-title">@CakeContext.Name</h5>
<p class="card-text">Price $@CakeContext.Cost</p>
</div>
<div class="card-footer text-muted">
Click Here
</div>
</div>
</ShowTemplate>
</ShowItems>
<SurveyPrompt Title="How is Blazor working for you?" />
<MyRootComponent Text="RootComponentText">
<MyFirstChildComponent>
<MySecondChildComponent>
<div>MySecondChildComponent - Content</div>
</MySecondChildComponent>
</MyFirstChildComponent>
</MyRootComponent>
<TestRenderFragment>
<div>Content of my TestRenderFragment</div>
</TestRenderFragment>
<p>
<b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>
-->
<div>
<Crafting Items="Items" Recipes="Recipes" />
</div>

@ -0,0 +1,58 @@
using System;
using BlazorApp.Components;
using BlazorApp.Models;
using BlazorApp.Services;
using Microsoft.AspNetCore.Components;
namespace BlazorApp.Pages
{
public partial class Index
{
/*
public List<Cake> Cakes { get; set; }
protected override Task OnAfterRenderAsync(bool firstRender)
{
LoadCakes();
StateHasChanged();
return base.OnAfterRenderAsync(firstRender);
}
public void LoadCakes()
{
Cakes = new List<Cake>
{
// items hidden for display purpose
new Cake
{
Id = 1,
Name = "Red Velvet",
Cost = 60
},
new Cake
{
Id = 2,
Name = "Black Forest",
Cost = 50
},
};
}
*/
[Inject]
public IDataService DataService { get; set; }
public List<Item> Items { get; set; } = new List<Item>();
private List<CraftingRecipe> Recipes { get; set; } = new List<CraftingRecipe>();
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
Items = await DataService.List(0, await DataService.Count());
Recipes = await DataService.GetRecipes();
}
}
}

@ -1,8 +1,7 @@
@page "/List" @page "/List"
@using BlazorApp.Models; @using BlazorApp.Models;
<h3>@Localizer["Title"]</h3>
<h3>List</h3>
<!-- <!--
@ -81,6 +80,7 @@
<DataGridColumn TItem="Item" Field="@nameof(Item.Id)" Caption="Action"> <DataGridColumn TItem="Item" Field="@nameof(Item.Id)" Caption="Action">
<DisplayTemplate> <DisplayTemplate>
<a href="Edit/@(context.Id)" class="btn btn-primary"><i class="fa fa-edit"></i> Editer</a> <a href="Edit/@(context.Id)" class="btn btn-primary"><i class="fa fa-edit"></i> Editer</a>
<button type="button" class="btn btn-primary" @onclick="() => OnDeleteAsync(context.Id)"><i class="fa fa-trash"></i> Supprimer</button>
</DisplayTemplate> </DisplayTemplate>
</DataGridColumn> </DataGridColumn>
</DataGrid> </DataGrid>

@ -1,8 +1,12 @@
using BlazorApp.Models; using BlazorApp.Modals;
using BlazorApp.Models;
using BlazorApp.Services; using BlazorApp.Services;
using Blazored.LocalStorage; using Blazored.LocalStorage;
using Blazored.Modal;
using Blazored.Modal.Services;
using Blazorise.DataGrid; using Blazorise.DataGrid;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
namespace BlazorApp.Pages namespace BlazorApp.Pages
{ {
@ -27,6 +31,12 @@ namespace BlazorApp.Pages
[Inject] [Inject]
public IDataService DataService { get; set; } public IDataService DataService { get; set; }
[Inject]
public IStringLocalizer<List> Localizer { get; set; }
[CascadingParameter]
public IModalService Modal { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender) protected override async Task OnAfterRenderAsync(bool firstRender)
{ {
// Do not treat this action if is not the first render // Do not treat this action if is not the first render
@ -59,5 +69,24 @@ namespace BlazorApp.Pages
totalItem = await DataService.Count(); totalItem = await DataService.Count();
} }
} }
private async Task OnDeleteAsync(int id)
{
var parameters = new ModalParameters();
parameters.Add(nameof(Item.Id), id);
var modal = Modal.Show<DeleteConfirmation>("Delete Confirmation", parameters);
var result = await modal.Result;
if (result.Cancelled)
{
return;
}
await DataService.Delete(id);
// Reload the page
NavigationManager.NavigateTo("list", true);
}
} }
} }

@ -0,0 +1,29 @@
@page "/pets1"
<h1>Pets</h1>
<TableTemplate Items="pets" Context="pet">
<TableHeader>
<th>ID</th>
<th>Name</th>
</TableHeader>
<RowTemplate>
<td>@pet.PetId</td>
<td>@pet.Name</td>
</RowTemplate>
</TableTemplate>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
new Pet { PetId = 4, Name = "Salem Saberhagen" },
new Pet { PetId = 7, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}

@ -0,0 +1,29 @@
@page "/pets2"
<h1>Pets</h1>
<TableTemplate Items="pets">
<TableHeader>
<th>ID</th>
<th>Name</th>
</TableHeader>
<RowTemplate Context="pet">
<td>@pet.PetId</td>
<td>@pet.Name</td>
</RowTemplate>
</TableTemplate>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
new Pet { PetId = 4, Name = "Salem Saberhagen" },
new Pet { PetId = 7, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}

@ -0,0 +1,29 @@
@page "/pets3"
<h1>Pets</h1>
<TableTemplate Items="pets">
<TableHeader>
<th>ID</th>
<th>Name</th>
</TableHeader>
<RowTemplate>
<td>@context.PetId</td>
<td>@context.Name</td>
</RowTemplate>
</TableTemplate>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
new Pet { PetId = 4, Name = "Salem Saberhagen" },
new Pet { PetId = 7, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}

@ -0,0 +1,29 @@
@page "/pets4"
<h1>Pets</h1>
<TableTemplate Items="pets" TItem="Pet">
<TableHeader>
<th>ID</th>
<th>Name</th>
</TableHeader>
<RowTemplate>
<td>@context.PetId</td>
<td>@context.Name</td>
</RowTemplate>
</TableTemplate>
@code {
private List<Pet> pets = new()
{
new Pet { PetId = 2, Name = "Mr. Bigglesworth" },
new Pet { PetId = 4, Name = "Salem Saberhagen" },
new Pet { PetId = 7, Name = "K-9" }
};
private class Pet
{
public int PetId { get; set; }
public string? Name { get; set; }
}
}

@ -11,6 +11,8 @@
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" /> <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link href="css/site.css" rel="stylesheet" /> <link href="css/site.css" rel="stylesheet" />
<link href="BlazorApp.styles.css" rel="stylesheet" /> <link href="BlazorApp.styles.css" rel="stylesheet" />
<link href="_content/Blazored.Modal/blazored-modal.css" rel="stylesheet" />
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" /> <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
</head> </head>
<body> <body>
@ -28,6 +30,9 @@
</div> </div>
<script src="_framework/blazor.server.js"></script> <script src="_framework/blazor.server.js"></script>
<script src="_content/Blazored.Modal/blazored.modal.js"></script>
<script src="Components/Crafting.razor.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css">

@ -6,6 +6,10 @@ using Blazorise.Bootstrap;
using Blazorise.Icons.FontAwesome; using Blazorise.Icons.FontAwesome;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.Web;
using Blazored.Modal;
using System.Globalization;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Localization;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@ -23,6 +27,25 @@ builder.Services.AddBlazoredLocalStorage();
builder.Services.AddScoped<IDataService, DataLocalService>(); builder.Services.AddScoped<IDataService, DataLocalService>();
builder.Services.AddBlazoredModal();
// Add the controller of the app
builder.Services.AddControllers();
// Add the localization to the app and specify the resources path
builder.Services.AddLocalization(opts => { opts.ResourcesPath = "Resources"; });
// Configure the localtization
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
// Set the default culture of the web site
options.DefaultRequestCulture = new RequestCulture(new CultureInfo("en-US"));
// Declare the supported culture
options.SupportedCultures = new List<CultureInfo> { new CultureInfo("en-US"), new CultureInfo("fr-FR") };
options.SupportedUICultures = new List<CultureInfo> { new CultureInfo("en-US"), new CultureInfo("fr-FR") };
});
var app = builder.Build(); var app = builder.Build();
// Configure the HTTP request pipeline. // Configure the HTTP request pipeline.
@ -39,6 +62,21 @@ app.UseStaticFiles();
app.UseRouting(); app.UseRouting();
// Get the current localization options
var options = ((IApplicationBuilder)app).ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
if (options?.Value != null)
{
// use the default localization
app.UseRequestLocalization(options.Value);
}
// Add the controller to the endpoint
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.MapBlazorHub(); app.MapBlazorHub();
app.MapFallbackToPage("/_Host"); app.MapFallbackToPage("/_Host");

@ -0,0 +1,60 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace BlazorApp.Resources {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// This class was generated by MSBuild using the GenerateResource task.
/// To add or remove a member, edit your .resx file then rerun MSBuild.
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Build.Tasks.StronglyTypedResourceBuilder", "15.1.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Pages_List {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Pages_List() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BlazorApp.Resources.Pages.List", typeof(Pages_List).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

@ -1,4 +1,6 @@
using System; using System;
using BlazorApp.Components;
using BlazorApp.Factories;
using BlazorApp.Models; using BlazorApp.Models;
using Blazored.LocalStorage; using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
@ -33,17 +35,7 @@ namespace BlazorApp.Services
model.Id = currentData.Max(s => s.Id) + 1; model.Id = currentData.Max(s => s.Id) + 1;
// Add the item to the current data // Add the item to the current data
currentData.Add(new Item currentData.Add(ItemFactory.Create(model));
{
Id = model.Id,
DisplayName = model.DisplayName,
Name = model.Name,
RepairWith = model.RepairWith,
EnchantCategories = model.EnchantCategories,
MaxDurability = model.MaxDurability,
StackSize = model.StackSize,
CreatedDate = DateTime.Now
});
// Save the image // Save the image
var imagePathInfo = new DirectoryInfo($"{_webHostEnvironment.WebRootPath}/images"); var imagePathInfo = new DirectoryInfo($"{_webHostEnvironment.WebRootPath}/images");
@ -143,17 +135,55 @@ namespace BlazorApp.Services
await File.WriteAllBytesAsync(fileName.FullName, model.ImageContent); await File.WriteAllBytesAsync(fileName.FullName, model.ImageContent);
// Modify the content of the item // Modify the content of the item
item.DisplayName = model.DisplayName; ItemFactory.Update(item, model);
item.Name = model.Name;
item.RepairWith = model.RepairWith;
item.EnchantCategories = model.EnchantCategories;
item.MaxDurability = model.MaxDurability;
item.StackSize = model.StackSize;
item.UpdatedDate = DateTime.Now;
// Save the data // Save the data
await _localStorage.SetItemAsync("data", currentData); await _localStorage.SetItemAsync("data", currentData);
} }
public async Task Delete(int id)
{
// Get the current data
var currentData = await _localStorage.GetItemAsync<List<Item>>("data");
// Get the item int the list
var item = currentData.FirstOrDefault(w => w.Id == id);
// Delete item in
currentData.Remove(item);
// Delete the image
var imagePathInfo = new DirectoryInfo($"{_webHostEnvironment.WebRootPath}/images");
var fileName = new FileInfo($"{imagePathInfo}/{item.Name}.png");
if (fileName.Exists)
{
File.Delete(fileName.FullName);
}
// Save the data
await _localStorage.SetItemAsync("data", currentData);
}
public Task<List<CraftingRecipe>> GetRecipes()
{
var items = new List<CraftingRecipe>
{
new CraftingRecipe
{
Give = new Item { DisplayName = "Diamond", Name = "diamond" },
Have = new List<List<string>>
{
new List<string> { "dirt", "dirt", "dirt" },
new List<string> { "dirt", null, "dirt" },
new List<string> { "dirt", "dirt", "dirt" }
}
}
};
return Task.FromResult(items);
}
} }
} }

@ -1,4 +1,5 @@
using System; using System;
using BlazorApp.Components;
using BlazorApp.Models; using BlazorApp.Models;
namespace BlazorApp.Services namespace BlazorApp.Services
@ -8,8 +9,12 @@ namespace BlazorApp.Services
Task Add(ItemModel model); Task Add(ItemModel model);
Task<int> Count(); Task<int> Count();
Task<Item> GetById(int id);
Task<List<Item>> List(int currentPage, int pageSize); Task<List<Item>> List(int currentPage, int pageSize);
Task Update(int id, ItemModel itemModel);
Task Delete(int id);
Task<List<CraftingRecipe>> GetRecipes();
} }
} }

@ -0,0 +1,43 @@
@using System.Globalization
@inject NavigationManager NavigationManager
<p>
<label>
Select your locale:
<select @bind="Culture">
@foreach (var culture in supportedCultures)
{
<option value="@culture">@culture.DisplayName</option>
}
</select>
</label>
</p>
@code
{
private CultureInfo[] supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("fr-FR")
};
private CultureInfo Culture
{
get => CultureInfo.CurrentCulture;
set
{
if (CultureInfo.CurrentUICulture == value)
{
return;
}
var culture = value.Name.ToLower(CultureInfo.InvariantCulture);
var uri = new Uri(this.NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
var query = $"?culture={Uri.EscapeDataString(culture)}&" + $"redirectUri={Uri.EscapeDataString(uri)}";
// Redirect the user to the culture controller to set the cookie
this.NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
}
}
}

@ -10,6 +10,10 @@
<main> <main>
<div class="top-row px-4"> <div class="top-row px-4">
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a> <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
<div class="px-4">
<CultureSelector />
</div>
</div> </div>
<article class="content px-4"> <article class="content px-4">

@ -0,0 +1,28 @@
@typeparam TItem
@using System.Diagnostics.CodeAnalysis
<table class="table">
<thead>
<tr>@TableHeader</tr>
</thead>
<tbody>
@foreach (var item in Items)
{
if (RowTemplate is not null)
{
<tr>@RowTemplate(item)</tr>
}
}
</tbody>
</table>
@code {
[Parameter]
public RenderFragment? TableHeader { get; set; }
[Parameter]
public RenderFragment<TItem>? RowTemplate { get; set; }
[Parameter, AllowNull]
public IReadOnlyList<TItem> Items { get; set; }
}

@ -9,3 +9,5 @@
@using BlazorApp @using BlazorApp
@using BlazorApp.Shared @using BlazorApp.Shared
@using Blazorise.DataGrid @using Blazorise.DataGrid
@using Blazored.Modal
@using Blazored.Modal.Services

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Loading…
Cancel
Save