Compare commits

..

1 Commits

Author SHA1 Message Date
Marc CHEVALDONNE 54101e17b5 Component subcomponent page
continuous-integration/drone/push Build is passing Details
2 years ago

@ -21,4 +21,4 @@ steps:
volumes:
- name: docs
temp: {}
temp: {}

@ -1,161 +1,161 @@
---
sidebar_position: 5
title: Creation of the add model
---
## Add model
In order to add an element we will create an object representing our item.
For this in create a new class `Models/ItemModel.cs`, this class will include all the information of our API object.
We will also add a property so that the user accepts the conditions of addition.
Similarly, annotations will be present to validate the fields of our forms.
```csharp title="Models/ItemModel.cs"
public class ItemModel
{
public int Id { get; set; }
[Required]
[StringLength(50, ErrorMessage = "The display name must not exceed 50 characters.")]
public string DisplayName { get; set; }
[Required]
[StringLength(50, ErrorMessage = "The name must not exceed 50 characters.")]
[RegularExpression(@"^[a-z''-'\s]{1,50}$", ErrorMessage = "Only lowercase characters are accepted.")]
public string Name { get; set; }
[Required]
[Range(1, 64)]
public int StackSize { get; set; }
[Required]
[Range(1, 125)]
public int MaxDurability { get; set; }
public List<string> EnchantCategories { get; set; }
public List<string> RepairWith { get; set; }
[Required]
[Range(typeof(bool), "true", "true", ErrorMessage = "You must agree to the terms.")]
public bool AcceptCondition { get; set; }
[Required(ErrorMessage = "The image of the item is mandatory!")]
public byte[] ImageContent { get; set; }
}
```
## Concept: Data Annotation
### Validation attributes
Validation attributes allow you to specify validation rules for model properties.
The following example shows a model class that is annotated with validation attributes.
The `[ClassicMovie]` attribute is a custom validation attribute, and the others are predefined.
```csharp
public class Movie
{
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Title { get; set; }
[ClassicMovie(1960)]
[DataType(DataType.Date)]
[Display(Name = "Release Date")]
public DateTime ReleaseDate { get; set; }
[Required]
[StringLength(1000)]
public string Description { get; set; }
[Range(0, 999.99)]
public decimal Price { get; set; }
public Genre Genre { get; set; }
public bool Preorder { get; set; }
}
```
### Attributs prédéfinis
Here are some of the predefined validation attributes:
* `[ValidateNever]`: ValidateNeverAttribute Indicates that a property or parameter should be excluded from validation.
* `[CreditCard]`: Checks that the property has a credit card format. Requires additional jQuery validation methods.
* `[Compare]`: Validates that two properties of a model match.
* `[EmailAddress]`: Checks that the property has an email format.
* `[Phone]`: Checks that the property has a phone number format.
* `[Range]`: Checks that the property value is within a specified range.
* `[RegularExpression]`: Validates that the property value matches a specified regular expression.
* `[Required]`: Checks that the field is not null. For more information on the behavior of this attribute, see [Required] attribute.
* `[StringLength]`: Validates that a property value of type String does not exceed a specified length limit.
* `[Url]`: Checks that the property has a URL format.
* `[Remote]`: Validates input on the client by calling an action method on the server. For more information on the behavior of this attribute, see [Remote] attribute.
You can find the full list of validation attributes in the [System.ComponentModel.DataAnnotations](https://docs.microsoft.com/fr-fr/dotnet/api/system.componentmodel.dataannotations) namespace.
### Error Messages
Validation attributes allow you to specify the error message to display for invalid input. For instance :
```csharp
[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]
```
Internally the attributes call `String.Format` with a placeholder for the field name and sometimes other placeholders. For instance :
```csharp
[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]
```
Applied to a `Name` property, the error message created by the previous code would be "Name length must be between 6 and 8".
To find out what parameters are passed to `String.Format` for the error message of a particular attribute, see the [DataAnnotations source code](https://github.com/dotnet/runtime/tree/main/src /libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations).
### Custom attributes
For scenarios not handled by the predefined validation attributes, you can create custom validation attributes. Create a class that inherits from ValidationAttribute and override the IsValid method.
The `IsValid` method accepts an object named value, which is the input to validate. An overload also accepts a `ValidationContext` object, which provides additional information such as the model instance created by the model binding.
The following example checks that the release date of a movie belonging to the Classic genre is not later than a specified year. The `[ClassicMovie]` attribute:
* Runs only on the server.
* For classic films, validate the publication date:
```csharp
public class ClassicMovieAttribute : ValidationAttribute
{
public ClassicMovieAttribute(int year)
{
Year = year;
}
public int Year { get; }
public string GetErrorMessage() =>
$"Classic movies must have a release year no later than {Year}.";
protected override ValidationResult IsValid(object value,
ValidationContext validationContext)
{
var movie = (Movie)validationContext.ObjectInstance;
var releaseYear = ((DateTime)value).Year;
if (movie.Genre == Genre.Classic && releaseYear > Year)
{
return new ValidationResult(GetErrorMessage());
}
return ValidationResult.Success;
}
}
```
The `movie` variable in the previous example represents a `Movie` object that contains the form submission data. When validation fails, a `ValidationResult` with an error message is returned.
---
sidebar_position: 5
title: Creation of the add model
---
## Add model
In order to add an element we will create an object representing our item.
For this in create a new class `Models/ItemModel.cs`, this class will include all the information of our API object.
We will also add a property so that the user accepts the conditions of addition.
Similarly, annotations will be present to validate the fields of our forms.
```csharp title="Models/ItemModel.cs"
public class ItemModel
{
public int Id { get; set; }
[Required]
[StringLength(50, ErrorMessage = "The display name must not exceed 50 characters.")]
public string DisplayName { get; set; }
[Required]
[StringLength(50, ErrorMessage = "The name must not exceed 50 characters.")]
[RegularExpression(@"^[a-z''-'\s]{1,40}$", ErrorMessage = "Only lowercase characters are accepted.")]
public string Name { get; set; }
[Required]
[Range(1, 64)]
public int StackSize { get; set; }
[Required]
[Range(1, 125)]
public int MaxDurability { get; set; }
public List<string> EnchantCategories { get; set; }
public List<string> RepairWith { get; set; }
[Required]
[Range(typeof(bool), "true", "true", ErrorMessage = "You must agree to the terms.")]
public bool AcceptCondition { get; set; }
[Required(ErrorMessage = "The image of the item is mandatory!")]
public byte[] ImageContent { get; set; }
}
```
## Concept: Data Annotation
### Validation attributes
Validation attributes allow you to specify validation rules for model properties.
The following example shows a model class that is annotated with validation attributes.
The `[ClassicMovie]` attribute is a custom validation attribute, and the others are predefined.
```csharp
public class Movie
{
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Title { get; set; }
[ClassicMovie(1960)]
[DataType(DataType.Date)]
[Display(Name = "Release Date")]
public DateTime ReleaseDate { get; set; }
[Required]
[StringLength(1000)]
public string Description { get; set; }
[Range(0, 999.99)]
public decimal Price { get; set; }
public Genre Genre { get; set; }
public bool Preorder { get; set; }
}
```
### Attributs prédéfinis
Here are some of the predefined validation attributes:
* `[ValidateNever]`: ValidateNeverAttribute Indicates that a property or parameter should be excluded from validation.
* `[CreditCard]`: Checks that the property has a credit card format. Requires additional jQuery validation methods.
* `[Compare]`: Validates that two properties of a model match.
* `[EmailAddress]`: Checks that the property has an email format.
* `[Phone]`: Checks that the property has a phone number format.
* `[Range]`: Checks that the property value is within a specified range.
* `[RegularExpression]`: Validates that the property value matches a specified regular expression.
* `[Required]`: Checks that the field is not null. For more information on the behavior of this attribute, see [Required] attribute.
* `[StringLength]`: Validates that a property value of type String does not exceed a specified length limit.
* `[Url]`: Checks that the property has a URL format.
* `[Remote]`: Validates input on the client by calling an action method on the server. For more information on the behavior of this attribute, see [Remote] attribute.
You can find the full list of validation attributes in the [System.ComponentModel.DataAnnotations](https://docs.microsoft.com/fr-fr/dotnet/api/system.componentmodel.dataannotations) namespace.
### Error Messages
Validation attributes allow you to specify the error message to display for invalid input. For instance :
```csharp
[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]
```
Internally the attributes call `String.Format` with a placeholder for the field name and sometimes other placeholders. For instance :
```csharp
[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]
```
Applied to a `Name` property, the error message created by the previous code would be "Name length must be between 6 and 8".
To find out what parameters are passed to `String.Format` for the error message of a particular attribute, see the [DataAnnotations source code](https://github.com/dotnet/runtime/tree/main/src /libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations).
### Custom attributes
For scenarios not handled by the predefined validation attributes, you can create custom validation attributes. Create a class that inherits from ValidationAttribute and override the IsValid method.
The `IsValid` method accepts an object named value, which is the input to validate. An overload also accepts a `ValidationContext` object, which provides additional information such as the model instance created by the model binding.
The following example checks that the release date of a movie belonging to the Classic genre is not later than a specified year. The `[ClassicMovie]` attribute:
* Runs only on the server.
* For classic films, validate the publication date:
```csharp
public class ClassicMovieAttribute : ValidationAttribute
{
public ClassicMovieAttribute(int year)
{
Year = year;
}
public int Year { get; }
public string GetErrorMessage() =>
$"Classic movies must have a release year no later than {Year}.";
protected override ValidationResult IsValid(object value,
ValidationContext validationContext)
{
var movie = (Movie)validationContext.ObjectInstance;
var releaseYear = ((DateTime)value).Year;
if (movie.Genre == Genre.Classic && releaseYear > Year)
{
return new ValidationResult(GetErrorMessage());
}
return ValidationResult.Success;
}
}
```
The `movie` variable in the previous example represents a `Movie` object that contains the form submission data. When validation fails, a `ValidationResult` with an error message is returned.

@ -12,18 +12,45 @@ Open the `Pages/Add.razor.cs` file and add the highlighted lines:
```csharp title="Pages/Add.razor.cs"
public partial class Add
{
...
[Inject]
public ILocalStorageService LocalStorage { get; set; }
// highlight-start
[Inject]
public NavigationManager NavigationManager { get; set; }
// highlight-end
...
/// <summary>
/// The default roles.
/// </summary>
private List<string> roles = new List<string>() { "admin", "writter", "reader", "member" };
/// <summary>
/// The current data model
/// </summary>
private DataModel dataModel = new()
{
DateOfBirth = DateTime.Now,
Roles = new List<string>()
};
private async void HandleValidSubmit()
{
...
// Get the current data
var currentData = await LocalStorage.GetItemAsync<List<Data>>("data");
// Simulate the Id
dataModel.Id = currentData.Max(s => s.Id) + 1;
// Add the item to the current data
currentData.Add(new Data
{
LastName = dataModel.LastName,
DateOfBirth = dataModel.DateOfBirth,
FirstName = dataModel.FirstName,
Id = dataModel.Id,
Roles = dataModel.Roles
});
// Save the data
await LocalStorage.SetItemAsync("data", currentData);
@ -31,6 +58,24 @@ public partial class Add
// highlight-next-line
NavigationManager.NavigateTo("list");
}
private void OnRoleChange(string item, object checkedValue)
{
if ((bool)checkedValue)
{
if (!dataModel.Roles.Contains(item))
{
dataModel.Roles.Add(item);
}
return;
}
if (dataModel.Roles.Contains(item))
{
dataModel.Roles.Remove(item);
}
}
}
```

@ -110,10 +110,6 @@ builder.Services.AddScoped<IDataService, DataApiService>();
Download this [project](/Minecraft.Crafting.Api.zip).
:::caution
If you have a 404 error with the download, remove the last `/` at the end of the url. Example : `.zip/` => `.zip`
:::
Unzip the file in the directory of your project, at the same place of the directory of the Blazor Project.
Example:

@ -154,6 +154,8 @@ The following code:
```
```csharp title="Config.razor.cs"
private PositionOptions positionOptions;
public partial class Config
{
[Inject]

@ -13,12 +13,15 @@ Add the `Blazored.Modal` nuget.
// highlight-next-line
using Blazored.Modal;
...
public static async Task Main(string[] args)
{
...
// highlight-next-line
builder.Services.AddBlazoredModal();
builder.Services.AddBlazoredModal();
...
...
}
```
### Add Imports

@ -94,17 +94,6 @@ public class DataLocalService : IDataService
public async Task<int> Count()
{
// Load data from the local storage
var currentData = await _localStorage.GetItemAsync<Item[]>("data");
// Check if data exist in the local storage
if (currentData == null)
{
// this code add in the local storage the fake data
var originalData = await _http.GetFromJsonAsync<Item[]>($"{_navigationManager.BaseUri}fake-data.json");
await _localStorage.SetItemAsync("data", originalData);
}
return (await _localStorage.GetItemAsync<Item[]>("data")).Length;
}

@ -1,365 +1,365 @@
---
sidebar_position: 4
title: Creation of page editor
---
## Creation of the page
As before, create a new page which will be named `Edit.razor` and the partial class `Edit.razor.cs`.
## Final source code
```cshtml title="Pages/Edit.razor"
<h3>Edit</h3>
```
```csharp title="Pages/Edit.razor.cs"
public partial class Edit
{
}
```
## Set page url
We are going to define the url of our page by specifying that we want our identifier.
Open the `Pages/Edit.razor` file and add the highlighted edits as follows:
```cshtml title="Pages/Edit.razor"
// highlight-next-line
@page "/edit/{Id:int}"
<h3>Edit</h3>
```
## Pass a parameter
We passed in the url the id of our item to edit, now we are going to retrieve it in a `Parameter` in order to be able to use it in our code.
Open the `Pages/Edit.razor.cs` file and add the highlighted edits as follows:
```cshtml title="Pages/Edit.razor.cs"
public partial class Edit
{
[Parameter]
public int Id { get; set; }
}
```
## View Parameter
In order to verify the passage of our identifier we will display it.
Open the `Pages/Edit.razor` file and add the highlighted edits as follows:
```cshtml title="Pages/Edit.razor"
@page "/edit/{Id:int}"
<h3>Edit</h3>
// highlight-next-line
<div>My parameter: @Id</div>
```
## Concept: URL parameters
### Route settings
The router uses routing parameters to populate corresponding component parameters with the same name.
Route parameter names are case insensitive. In the following example, the `text` parameter assigns the value of the road segment to the component's `Text` property.
When a request is made for `/RouteParameter/amazing`, the `<h1>` tag content is rendered as `Blazor is amazing!`.
```cshtml title="Pages/RouteParameter.razor"
@page "/RouteParameter/{text}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string? Text { get; set; }
}
```
Optional parameters are supported.
In the following example, the optional `text` parameter assigns the value of the route segment to the component's `Text` property. If the segment is not present, the value of `Text` is set to `fantastic`.
```cshtml title="Pages/RouteParameter.razor"
@page "/RouteParameter/{text?}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string? Text { get; set; }
protected override void OnInitialized()
{
Text = Text ?? "fantastic";
}
}
```
Use `OnParametersSet OnInitialized{Async}` instead to allow navigation to the same component with a different optional parameter value.
Based on the previous example, use `OnParametersSet` when the user needs to navigate from `/RouteParameter` to `/RouteParameter/amazing` or from `/RouteParameter/amazing` to `/RouteParameter`:
```html
protected override void OnParametersSet()
{
Text = Text ?? "fantastic";
}
```
### Route Constraints
A route constraint applies type matching on a route segment to a component.
In the following example, the route to the `User` component matches only if:
* A routing `Id` segment is present in the request URL.
* The `Id` segment is an integer type ( `int` ).
```cshtml title="Pages/User.razor"
@page "/user/{Id:int}"
<h1>User Id: @Id</h1>
@code {
[Parameter]
public int Id { get; set; }
}
```
The route constraints shown in the following table are available.
For more information about route constraints that correspond to the indifferent culture, see the disclaimer below the table.
| Constraint | Example | Matching examples | Invariant culture correspondence
| ---- | ---- | ---- | ----
| `bool` | `{active:bool}` | `true`, FALSE | No
| `datetime` | `{dob:datetime}` | `2016-12-31`, `2016-12-31 7:32pm` | Yes
| `decimal` | `{price:decimal}` | `49.99`, `-1,000.01` | Yes
| `double` | `{weight:double}` | `1.234`, `-1,001.01e8` | Yes
| `float` | `{weight:float}` | `1.234, -1`,`001.01e8` | Yes
| `guid` | `{id:guid}` | `CD2C1638-1638-72D5-1638-DEADBEEF1638`, `{CD2C1638-1638-72D5-1638-DEADBEEF1638}` | No
| `int` | `{id:int}` | `123456789`, `-123456789` | Yes
| `long` | `{ticks:long}` | `123456789`, `-123456789` | Yes
:::caution
Routing constraints that check that the URL can be converted to a CLR type (like `int` or `DateTime`) always use the invariant culture. these constraints assume that the URL is not localizable.
:::
Route constraints also work with optional parameters. In the following example, `Id` is required, but `Option` is an optional boolean route parameter.
```cshtml title="Pages/User.razor"
@page "/user/{Id:int}/{Option:bool?}"
<p>
Id: @Id
</p>
<p>
Option: @Option
</p>
@code {
[Parameter]
public int Id { get; set; }
[Parameter]
public bool Option { get; set; }
}
```
## Concept: Component Parameters
Component parameters pass data to components and are set using Public C# Properties on the component class with the `[Parameter]` attribute.
In the following example, a built-in reference type ( `System.String` ) and a user-defined reference type ( `PanelBody` ) are passed as component parameters.
```csharp title="PanelBody.cs"
public class PanelBody
{
public string? Text { get; set; }
public string? Style { get; set; }
}
```
```cshtml title="Shared/ParameterChild.razor"
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">@Title</div>
<div class="card-body" style="font-style:@Body.Style">
@Body.Text
</div>
</div>
@code {
[Parameter]
public string Title { get; set; } = "Set By Child";
[Parameter]
public PanelBody Body { get; set; } =
new()
{
Text = "Set by child.",
Style = "normal"
};
}
```
:::caution
Providing initial values for component parameters is supported, but does not create a component that writes to its own parameters after the component is first rendered.
:::
The `Title` & `Body` component and `ParameterChild` component parameters are defined by arguments in the HTML tag that renders the component instance.
The following `ParameterParent` component renders two `ParameterChild` components:
* The first `ParameterChild` component is rendered without providing any parameter arguments.
* The second `ParameterChild` component receives values for `Title` and `Body` from the `ParameterParent` component, which uses an explicit C# expression to set the values for the properties of `PanelBody`.
```cshtml title="Pages/ParameterParent.razor"
@page "/parameter-parent"
<h1>Child component (without attribute values)</h1>
<ParameterChild />
<h1>Child component (with attribute values)</h1>
<ParameterChild Title="Set by Parent" Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />
```
The following rendered HTML markup of the `ParameterParent` component shows default `ParameterChild` values for components when the `ParameterParent` component does not provide component parameter values.
When the `ParameterParent` component provides component parameter values, they override the component's default `ParameterChild` values.
:::note
For clarity, rendered CSS style classes are not shown in the following rendered HTML markup.
:::
```html
<h1>Child component (without attribute values)</h1>
<div>
<div>Set By Child</div>
<div>Set by child.</div>
</div>
<h1>Child component (with attribute values)</h1>
<div>
<div>Set by Parent</div>
<div>Set by parent.</div>
</div>
```
Assign a C# field, property, or result of a method to a component parameter as an HTML attribute value using the `@` symbol.
The following `ParameterParent2` component displays four instances of the preceding `ParameterChild` component and sets their parameter `Title` values to:
* Value of the `title` field.
* Result of C# `GetTitle` method.
* Current local date in long format with `ToLongDateString`, which uses an implicit C# expression.
* `panelData` Property of the `Title` object.
```cshtml title="Pages/ParameterParent2.razor"
@page "/parameter-parent-2"
<ParameterChild Title="@title" />
<ParameterChild Title="@GetTitle()" />
<ParameterChild Title="@DateTime.Now.ToLongDateString()" />
<ParameterChild Title="@panelData.Title" />
@code {
private string title = "From Parent field";
private PanelData panelData = new();
private string GetTitle()
{
return "From Parent method";
}
private class PanelData
{
public string Title { get; set; } = "From Parent object";
}
}
```
:::info
When assigning a C# member to a component parameter, prefix the member with the `@` symbol and never prefix the parameter's HTML attribute.
Correct use:
```html
<ParameterChild Title="@title" />
```
Wrong:
```html
<ParameterChild @Title="title" />
```
:::
Using an explicit Razor expression to concatenate text with an expression result for assignment to a parameter is not supported.
The following example attempts to concatenate the text "Set by" with the property value of an object. The following Razor syntax is not supported:
```html
<ParameterChild Title="Set by @(panelData.Title)" />
```
The code in the previous example generates a Compiler Error when building the application:
```
Les attributs de composant ne prennent pas en charge le contenu complexe (mixte C# et balisage).
```
To support assigning a compound value, use a method, field, or property. The following example performs the concatenation of "`Set by`" and the property value of an object in the C# `GetTitle` method:
```cshtml title="Pages/ParameterParent3.razor"
@page "/parameter-parent-3"
<ParameterChild Title="@GetTitle()" />
@code {
private PanelData panelData = new();
private string GetTitle() => $"Set by {panelData.Title}";
private class PanelData
{
public string Title { get; set; } = "Parent";
}
}
```
Component parameters must be declared as Automatic Properties, which means they must not contain custom logic in their `get` or `set` accessors.
For example, the following `StartData` property is an automatic property:
```csharp
[Parameter]
public DateTime StartData { get; set; }
```
Do not put custom logic in the `get` or `set` accessor, as component parameters are purely for use as a channel from a parent component to pass information to a child component.
If a `set` accessor of a child component property contains logic that causes the parent component to be re-rendered, the results of an infinite render loop.
To transform a received parameter value:
* Leave the parameter property as auto property to represent the raw data provided.
* Create another property or method to provide the transformed data based on the parameter property.
Override `OnParametersSetAsync` to transform a received parameter each time new data is received.
Writing an initial value to a component parameter is supported because initial value assignments don't interfere with automatic component Blazor rendering.
The following assignment of the current locale `DateTime` with `DateTime.Now` to `StartData` is valid syntax in a component:
```csharp
[Parameter]
public DateTime StartData { get; set; } = DateTime.Now;
```
After the initial assignment of `DateTime.Now`, do not assign a value to `StartData` in code.
---
sidebar_position: 4
title: Creation of page editor
---
## Creation of the page
As before, create a new page which will be named `Edit.razor` and the partial class `Edit.razor.cs`.
## Final source code
```cshtml title="Pages/Edit.razor"
<h3>Edit</h3>
```
```csharp title="Pages/Edit.razor.cs"
public partial class Edit
{
}
```
## Set page url
We are going to define the url of our page by specifying that we want our identifier.
Open the `Pages/Edit.razor` file and add the highlighted edits as follows:
```cshtml title="Pages/Edit.razor"
// highlight-next-line
@page "/edit/{Id:int}"
<h3>Edit</h3>
```
## Pass a parameter
We passed in the url the id of our item to edit, now we are going to retrieve it in a `Parameter` in order to be able to use it in our code.
Open the `Pages/Edit.razor.cs` file and add the highlighted edits as follows:
```cshtml title="Pages/Edit.razor.cs"
public partial class Edit
{
[Parameter]
public int Id { get; set; }
}
```
## View Parameter
In order to verify the passage of our identifier we will display it.
Open the `Pages/Edit.razor` file and add the highlighted edits as follows:
```cshtml title="Pages/Edit.razor"
@page "/edit/{Id:int}"
<h3>Edit</h3>
// highlight-next-line
<div>My paremeter: @Id</div>
```
## Concept: URL parameters
### Route settings
The router uses routing parameters to populate corresponding component parameters with the same name.
Route parameter names are case insensitive. In the following example, the `text` parameter assigns the value of the road segment to the component's `Text` property.
When a request is made for `/RouteParameter/amazing`, the `<h1>` tag content is rendered as `Blazor is amazing!`.
```cshtml title="Pages/RouteParameter.razor"
@page "/RouteParameter/{text}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string? Text { get; set; }
}
```
Optional parameters are supported.
In the following example, the optional `text` parameter assigns the value of the route segment to the component's `Text` property. If the segment is not present, the value of `Text` is set to `fantastic`.
```cshtml title="Pages/RouteParameter.razor"
@page "/RouteParameter/{text?}"
<h1>Blazor is @Text!</h1>
@code {
[Parameter]
public string? Text { get; set; }
protected override void OnInitialized()
{
Text = Text ?? "fantastic";
}
}
```
Use `OnParametersSet OnInitialized{Async}` instead to allow navigation to the same component with a different optional parameter value.
Based on the previous example, use `OnParametersSet` when the user needs to navigate from `/RouteParameter` to `/RouteParameter/amazing` or from `/RouteParameter/amazing` to `/RouteParameter`:
```html
protected override void OnParametersSet()
{
Text = Text ?? "fantastic";
}
```
### Route Constraints
A route constraint applies type matching on a route segment to a component.
In the following example, the route to the `User` component matches only if:
* A routing `Id` segment is present in the request URL.
* The `Id` segment is an integer type ( `int` ).
```cshtml title="Pages/User.razor"
@page "/user/{Id:int}"
<h1>User Id: @Id</h1>
@code {
[Parameter]
public int Id { get; set; }
}
```
The route constraints shown in the following table are available.
For more information about route constraints that correspond to the indifferent culture, see the disclaimer below the table.
| Constraint | Example | Matching examples | Invariant culture correspondence
| ---- | ---- | ---- | ----
| `bool` | `{active:bool}` | `true`, FALSE | No
| `datetime` | `{dob:datetime}` | `2016-12-31`, `2016-12-31 7:32pm` | Yes
| `decimal` | `{price:decimal}` | `49.99`, `-1,000.01` | Yes
| `double` | `{weight:double}` | `1.234`, `-1,001.01e8` | Yes
| `float` | `{weight:float}` | `1.234, -1`,`001.01e8` | Yes
| `guid` | `{id:guid}` | `CD2C1638-1638-72D5-1638-DEADBEEF1638`, `{CD2C1638-1638-72D5-1638-DEADBEEF1638}` | No
| `int` | `{id:int}` | `123456789`, `-123456789` | Yes
| `long` | `{ticks:long}` | `123456789`, `-123456789` | Yes
:::caution
Routing constraints that check that the URL can be converted to a CLR type (like `int` or `DateTime`) always use the invariant culture. these constraints assume that the URL is not localizable.
:::
Route constraints also work with optional parameters. In the following example, `Id` is required, but `Option` is an optional boolean route parameter.
```cshtml title="Pages/User.razor"
@page "/user/{Id:int}/{Option:bool?}"
<p>
Id: @Id
</p>
<p>
Option: @Option
</p>
@code {
[Parameter]
public int Id { get; set; }
[Parameter]
public bool Option { get; set; }
}
```
## Concept: Component Parameters
Component parameters pass data to components and are set using Public C# Properties on the component class with the `[Parameter]` attribute.
In the following example, a built-in reference type ( `System.String` ) and a user-defined reference type ( `PanelBody` ) are passed as component parameters.
```csharp title="PanelBody.cs"
public class PanelBody
{
public string? Text { get; set; }
public string? Style { get; set; }
}
```
```cshtml title="Shared/ParameterChild.razor"
<div class="card w-25" style="margin-bottom:15px">
<div class="card-header font-weight-bold">@Title</div>
<div class="card-body" style="font-style:@Body.Style">
@Body.Text
</div>
</div>
@code {
[Parameter]
public string Title { get; set; } = "Set By Child";
[Parameter]
public PanelBody Body { get; set; } =
new()
{
Text = "Set by child.",
Style = "normal"
};
}
```
:::caution
Providing initial values for component parameters is supported, but does not create a component that writes to its own parameters after the component is first rendered.
:::
The `Title` & `Body` component and `ParameterChild` component parameters are defined by arguments in the HTML tag that renders the component instance.
The following `ParameterParent` component renders two `ParameterChild` components:
* The first `ParameterChild` component is rendered without providing any parameter arguments.
* The second `ParameterChild` component receives values for `Title` and `Body` from the `ParameterParent` component, which uses an explicit C# expression to set the values for the properties of `PanelBody`.
```cshtml title="Pages/ParameterParent.razor"
@page "/parameter-parent"
<h1>Child component (without attribute values)</h1>
<ParameterChild />
<h1>Child component (with attribute values)</h1>
<ParameterChild Title="Set by Parent" Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />
```
The following rendered HTML markup of the `ParameterParent` component shows default `ParameterChild` values for components when the `ParameterParent` component does not provide component parameter values.
When the `ParameterParent` component provides component parameter values, they override the component's default `ParameterChild` values.
:::note
For clarity, rendered CSS style classes are not shown in the following rendered HTML markup.
:::
```html
<h1>Child component (without attribute values)</h1>
<div>
<div>Set By Child</div>
<div>Set by child.</div>
</div>
<h1>Child component (with attribute values)</h1>
<div>
<div>Set by Parent</div>
<div>Set by parent.</div>
</div>
```
Assign a C# field, property, or result of a method to a component parameter as an HTML attribute value using the `@` symbol.
The following `ParameterParent2` component displays four instances of the preceding `ParameterChild` component and sets their parameter `Title` values to:
* Value of the `title` field.
* Result of C# `GetTitle` method.
* Current local date in long format with `ToLongDateString`, which uses an implicit C# expression.
* `panelData` Property of the `Title` object.
```cshtml title="Pages/ParameterParent2.razor"
@page "/parameter-parent-2"
<ParameterChild Title="@title" />
<ParameterChild Title="@GetTitle()" />
<ParameterChild Title="@DateTime.Now.ToLongDateString()" />
<ParameterChild Title="@panelData.Title" />
@code {
private string title = "From Parent field";
private PanelData panelData = new();
private string GetTitle()
{
return "From Parent method";
}
private class PanelData
{
public string Title { get; set; } = "From Parent object";
}
}
```
:::info
When assigning a C# member to a component parameter, prefix the member with the `@` symbol and never prefix the parameter's HTML attribute.
Correct use:
```html
<ParameterChild Title="@title" />
```
Wrong:
```html
<ParameterChild @Title="title" />
```
:::
Using an explicit Razor expression to concatenate text with an expression result for assignment to a parameter is not supported.
The following example attempts to concatenate the text "Set by" with the property value of an object. The following Razor syntax is not supported:
```html
<ParameterChild Title="Set by @(panelData.Title)" />
```
The code in the previous example generates a Compiler Error when building the application:
```
Les attributs de composant ne prennent pas en charge le contenu complexe (mixte C# et balisage).
```
To support assigning a compound value, use a method, field, or property. The following example performs the concatenation of "`Set by`" and the property value of an object in the C# `GetTitle` method:
```cshtml title="Pages/ParameterParent3.razor"
@page "/parameter-parent-3"
<ParameterChild Title="@GetTitle()" />
@code {
private PanelData panelData = new();
private string GetTitle() => $"Set by {panelData.Title}";
private class PanelData
{
public string Title { get; set; } = "Parent";
}
}
```
Component parameters must be declared as Automatic Properties, which means they must not contain custom logic in their `get` or `set` accessors.
For example, the following `StartData` property is an automatic property:
```csharp
[Parameter]
public DateTime StartData { get; set; }
```
Do not put custom logic in the `get` or `set` accessor, as component parameters are purely for use as a channel from a parent component to pass information to a child component.
If a `set` accessor of a child component property contains logic that causes the parent component to be re-rendered, the results of an infinite render loop.
To transform a received parameter value:
* Leave the parameter property as auto property to represent the raw data provided.
* Create another property or method to provide the transformed data based on the parameter property.
Override `OnParametersSetAsync` to transform a received parameter each time new data is received.
Writing an initial value to a component parameter is supported because initial value assignments don't interfere with automatic component Blazor rendering.
The following assignment of the current locale `DateTime` with `DateTime.Now` to `StartData` is valid syntax in a component:
```csharp
[Parameter]
public DateTime StartData { get; set; } = DateTime.Now;
```
After the initial assignment of `DateTime.Now`, do not assign a value to `StartData` in code.

@ -130,9 +130,11 @@ The following code:
New title
<input @bind="newHeading" />
</label>
// highlight-next-line
// highlight-start
<button @onclick="UpdateHeading">
Update heading
</button>
// highlight-end
</p>
<p>

@ -78,19 +78,12 @@ public partial class Index
private List<CraftingRecipe> Recipes { get; set; } = new List<CraftingRecipe>();
protected override async Task OnAfterRenderAsync(bool firstRender)
protected override async Task OnInitializedAsync()
{
base.OnAfterRenderAsync(firstRender);
if (!firstRender)
{
return;
}
await base.OnInitializedAsync();
Items = await DataService.List(0, await DataService.Count());
Recipes = await DataService.GetRecipes();
StateHasChanged();
}
}
```

@ -65,46 +65,44 @@ From now on our page will be available from the `/list` address of our site.
Open the `Shared/NavMenu.razor` file and add the highlighted lines:
```cshtml title="Shared/NavMenu.razor"
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">TO_DELETE_BlazorApp30000</a>
<button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
<div class="top-row pl-4 navbar navbar-dark">
<a class="navbar-brand" href="">MyBeautifulAdmin</a>
<button class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<nav class="flex-column">
<ul class="nav flex-column">
// highlight-start
<div class="nav-item px-3">
<NavLink class="nav-link" href="list" Match="NavLinkMatch.All">
<li class="nav-item px-3">
<NavLink class="nav-link" href="list">
<span class="oi oi-list-rich" aria-hidden="true"></span> List
</NavLink>
</div>
</li>
// highlight-end
<div class="nav-item px-3">
<li class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</div>
<div class="nav-item px-3">
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</div>
<div class="nav-item px-3">
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
</NavLink>
</div>
</nav>
</li>
</ul>
</div>
@code {
private bool collapseNavMenu = true;
private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private void ToggleNavMenu()
{

@ -40,7 +40,7 @@ For the bravest (**optional**):
Here are the item list specifications:
* The list must have pagination.
* The name and image of the elements must be present.
* A search field will filter the elements.
* A search field will filter the elements, the filtering must be done on the server side and not by the list.
* It must be possible to sort items by their names.
## Mockup

@ -1,161 +1,161 @@
---
sidebar_position: 5
title: Création du modèle d'ajout
---
## Modèle d'ajout
Afin d'ajouter un element nous allons créer un objet représentant notre item.
Pour cela dans créer une nouvelle classe `Models/ItemModel.cs`, cette classe comprendra l'ensemble des informations de notre objet de l'API.
Nous allons aussi ajouter une propriété afin que l'utilisation accepte les conditions d'ajout.
De même des annotations seront présentent afin de valider les champs de notre formulaires.
```csharp title="Models/ItemModel.cs"
public class ItemModel
{
public int Id { get; set; }
[Required]
[StringLength(50, ErrorMessage = "Le nom affiché ne doit pas dépasser 50 caractères.")]
public string DisplayName { get; set; }
[Required]
[StringLength(50, ErrorMessage = "Le nom ne doit pas dépasser 50 caractères.")]
[RegularExpression(@"^[a-z''-'\s]{1,50}$", ErrorMessage = "Seulement les caractères en minuscule sont acceptées.")]
public string Name { get; set; }
[Required]
[Range(1, 64)]
public int StackSize { get; set; }
[Required]
[Range(1, 125)]
public int MaxDurability { get; set; }
public List<string> EnchantCategories { get; set; }
public List<string> RepairWith { get; set; }
[Required]
[Range(typeof(bool), "true", "true", ErrorMessage = "Vous devez accepter les conditions.")]
public bool AcceptCondition { get; set; }
[Required(ErrorMessage = "L'image de l'item est obligatoire !")]
public byte[] ImageContent { get; set; }
}
```
## Notion : Data Annotation
### Attributs de validation
Les attributs de validation vous permettent de spécifier des règles de validation pour des propriétés de modèle.
Lexemple suivant montre une classe de modèle qui est annotée avec des attributs de validation.
Lattribut `[ClassicMovie]` est un attribut de validation personnalisé, et les autres sont prédéfinis.
```csharp
public class Movie
{
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Title { get; set; }
[ClassicMovie(1960)]
[DataType(DataType.Date)]
[Display(Name = "Release Date")]
public DateTime ReleaseDate { get; set; }
[Required]
[StringLength(1000)]
public string Description { get; set; }
[Range(0, 999.99)]
public decimal Price { get; set; }
public Genre Genre { get; set; }
public bool Preorder { get; set; }
}
```
### Attributs prédéfinis
Voici certains des attributs de validation prédéfinis :
* `[ValidateNever]`: ValidateNeverAttribute Indique quune propriété ou un paramètre doit être exclu de la validation.
* `[CreditCard]`: Vérifie que la propriété a un format de carte de crédit. Requiert des méthodes supplémentaires de validation jQuery.
* `[Compare]`: Valide que deux propriétés dun modèle correspondent.
* `[EmailAddress]`: Vérifie que la propriété a un format de-mail.
* `[Phone]`: Vérifie que la propriété a un format de numéro de téléphone.
* `[Range]`: Vérifie que la valeur de la propriété est comprise dans une plage spécifiée.
* `[RegularExpression]`: Valide le fait que la valeur de propriété corresponde à une expression régulière spécifiée.
* `[Required]`: Vérifie que le champ na pas la valeur null. Pour plus dinformations sur le comportement de cet attribut, consultez [Required] attribut .
* `[StringLength]`: Valide le fait quune valeur de propriété de type chaîne ne dépasse pas une limite de longueur spécifiée.
* `[Url]`: Vérifie que la propriété a un format dURL.
* `[Remote]`: Valide lentrée sur le client en appelant une méthode daction sur le serveur. Pour plus dinformations sur le comportement de cet attribut, consultez [Remote] attribut .
Vous trouverez la liste complète des attributs de validation dans lespace de noms [System.ComponentModel.DataAnnotations](https://docs.microsoft.com/fr-fr/dotnet/api/system.componentmodel.dataannotations).
### Messages derreur
Les attributs de validation vous permettent de spécifier le message derreur à afficher pour lentrée non valide. Par exemple :
```csharp
[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]
```
En interne, les attributs appellent `String.Format` avec un espace réservé pour le nom de champ et parfois dautres espaces réservés. Par exemple :
```csharp
[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]
```
Appliqué à une propriété `Name`, le message derreur créé par le code précédent serait « Name length must be between 6 and 8 ».
Pour savoir quels paramètres sont passés à `String.Format` pour le message derreur dun attribut particulier, consultez le [code source de DataAnnotations](https://github.com/dotnet/runtime/tree/main/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations).
### Attributs personnalisés
Pour les scénarios non gérés par les attributs de validation prédéfinis, vous pouvez créer des attributs de validation personnalisés. Créez une classe qui hérite de ValidationAttribute et substituez la méthode IsValid.
La méthode `IsValid` accepte un objet nommé value, qui est lentrée à valider. Une surcharge accepte également un objet `ValidationContext`, qui fournit des informations supplémentaires telles que linstance de modèle créée par la liaison de modèle.
Lexemple suivant vérifie que la date de sortie dun film appartenant au genre Classic nest pas ultérieure à une année spécifiée. L'attribut `[ClassicMovie]`:
* Sexécute uniquement sur le serveur.
* Pour les films classiques, valide la date de publication :
```csharp
public class ClassicMovieAttribute : ValidationAttribute
{
public ClassicMovieAttribute(int year)
{
Year = year;
}
public int Year { get; }
public string GetErrorMessage() =>
$"Classic movies must have a release year no later than {Year}.";
protected override ValidationResult IsValid(object value,
ValidationContext validationContext)
{
var movie = (Movie)validationContext.ObjectInstance;
var releaseYear = ((DateTime)value).Year;
if (movie.Genre == Genre.Classic && releaseYear > Year)
{
return new ValidationResult(GetErrorMessage());
}
return ValidationResult.Success;
}
}
```
La variable `movie` de lexemple précédent représente un objet `Movie` qui contient les données de lenvoi du formulaire. Quand la validation échoue, un `ValidationResult` avec un message derreur est retourné.
---
sidebar_position: 5
title: Création du modèle d'ajout
---
## Modèle d'ajout
Afin d'ajouter un element nous allons créer un objet représentant notre item.
Pour cela dans créer une nouvelle classe `Models/ItemModel.cs`, cette classe comprendra l'ensemble des informations de notre objet de l'API.
Nous allons aussi ajouter une propriété afin que l'utilisation accepte les conditions d'ajout.
De même des annotations seront présentent afin de valider les champs de notre formulaires.
```csharp title="Models/ItemModel.cs"
public class ItemModel
{
public int Id { get; set; }
[Required]
[StringLength(50, ErrorMessage = "Le nom affiché ne doit pas dépasser 50 caractères.")]
public string DisplayName { get; set; }
[Required]
[StringLength(50, ErrorMessage = "Le nom ne doit pas dépasser 50 caractères.")]
[RegularExpression(@"^[a-z''-'\s]{1,40}$", ErrorMessage = "Seulement les caractères en minuscule sont acceptées.")]
public string Name { get; set; }
[Required]
[Range(1, 64)]
public int StackSize { get; set; }
[Required]
[Range(1, 125)]
public int MaxDurability { get; set; }
public List<string> EnchantCategories { get; set; }
public List<string> RepairWith { get; set; }
[Required]
[Range(typeof(bool), "true", "true", ErrorMessage = "Vous devez accepter les conditions.")]
public bool AcceptCondition { get; set; }
[Required(ErrorMessage = "L'image de l'item est obligatoire !")]
public byte[] ImageContent { get; set; }
}
```
## Notion : Data Annotation
### Attributs de validation
Les attributs de validation vous permettent de spécifier des règles de validation pour des propriétés de modèle.
Lexemple suivant montre une classe de modèle qui est annotée avec des attributs de validation.
Lattribut `[ClassicMovie]` est un attribut de validation personnalisé, et les autres sont prédéfinis.
```csharp
public class Movie
{
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Title { get; set; }
[ClassicMovie(1960)]
[DataType(DataType.Date)]
[Display(Name = "Release Date")]
public DateTime ReleaseDate { get; set; }
[Required]
[StringLength(1000)]
public string Description { get; set; }
[Range(0, 999.99)]
public decimal Price { get; set; }
public Genre Genre { get; set; }
public bool Preorder { get; set; }
}
```
### Attributs prédéfinis
Voici certains des attributs de validation prédéfinis :
* `[ValidateNever]`: ValidateNeverAttribute Indique quune propriété ou un paramètre doit être exclu de la validation.
* `[CreditCard]`: Vérifie que la propriété a un format de carte de crédit. Requiert des méthodes supplémentaires de validation jQuery.
* `[Compare]`: Valide que deux propriétés dun modèle correspondent.
* `[EmailAddress]`: Vérifie que la propriété a un format de-mail.
* `[Phone]`: Vérifie que la propriété a un format de numéro de téléphone.
* `[Range]`: Vérifie que la valeur de la propriété est comprise dans une plage spécifiée.
* `[RegularExpression]`: Valide le fait que la valeur de propriété corresponde à une expression régulière spécifiée.
* `[Required]`: Vérifie que le champ na pas la valeur null. Pour plus dinformations sur le comportement de cet attribut, consultez [Required] attribut .
* `[StringLength]`: Valide le fait quune valeur de propriété de type chaîne ne dépasse pas une limite de longueur spécifiée.
* `[Url]`: Vérifie que la propriété a un format dURL.
* `[Remote]`: Valide lentrée sur le client en appelant une méthode daction sur le serveur. Pour plus dinformations sur le comportement de cet attribut, consultez [Remote] attribut .
Vous trouverez la liste complète des attributs de validation dans lespace de noms [System.ComponentModel.DataAnnotations](https://docs.microsoft.com/fr-fr/dotnet/api/system.componentmodel.dataannotations).
### Messages derreur
Les attributs de validation vous permettent de spécifier le message derreur à afficher pour lentrée non valide. Par exemple :
```csharp
[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]
```
En interne, les attributs appellent `String.Format` avec un espace réservé pour le nom de champ et parfois dautres espaces réservés. Par exemple :
```csharp
[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]
```
Appliqué à une propriété `Name`, le message derreur créé par le code précédent serait « Name length must be between 6 and 8 ».
Pour savoir quels paramètres sont passés à `String.Format` pour le message derreur dun attribut particulier, consultez le [code source de DataAnnotations](https://github.com/dotnet/runtime/tree/main/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations).
### Attributs personnalisés
Pour les scénarios non gérés par les attributs de validation prédéfinis, vous pouvez créer des attributs de validation personnalisés. Créez une classe qui hérite de ValidationAttribute et substituez la méthode IsValid.
La méthode `IsValid` accepte un objet nommé value, qui est lentrée à valider. Une surcharge accepte également un objet `ValidationContext`, qui fournit des informations supplémentaires telles que linstance de modèle créée par la liaison de modèle.
Lexemple suivant vérifie que la date de sortie dun film appartenant au genre Classic nest pas ultérieure à une année spécifiée. L'attribut `[ClassicMovie]`:
* Sexécute uniquement sur le serveur.
* Pour les films classiques, valide la date de publication :
```csharp
public class ClassicMovieAttribute : ValidationAttribute
{
public ClassicMovieAttribute(int year)
{
Year = year;
}
public int Year { get; }
public string GetErrorMessage() =>
$"Classic movies must have a release year no later than {Year}.";
protected override ValidationResult IsValid(object value,
ValidationContext validationContext)
{
var movie = (Movie)validationContext.ObjectInstance;
var releaseYear = ((DateTime)value).Year;
if (movie.Genre == Genre.Classic && releaseYear > Year)
{
return new ValidationResult(GetErrorMessage());
}
return ValidationResult.Success;
}
}
```
La variable `movie` de lexemple précédent représente un objet `Movie` qui contient les données de lenvoi du formulaire. Quand la validation échoue, un `ValidationResult` avec un message derreur est retourné.

@ -12,18 +12,45 @@ Ouvrez le fichier `Pages/Add.razor.cs` et ajouter les lignes en surbrillances :
```csharp title="Pages/Add.razor.cs"
public partial class Add
{
...
[Inject]
public ILocalStorageService LocalStorage { get; set; }
// highlight-start
[Inject]
public NavigationManager NavigationManager { get; set; }
// highlight-end
...
/// <summary>
/// The default roles.
/// </summary>
private List<string> roles = new List<string>() { "admin", "writter", "reader", "member" };
/// <summary>
/// The current data model
/// </summary>
private DataModel dataModel = new()
{
DateOfBirth = DateTime.Now,
Roles = new List<string>()
};
private async void HandleValidSubmit()
{
...
// Get the current data
var currentData = await LocalStorage.GetItemAsync<List<Data>>("data");
// Simulate the Id
dataModel.Id = currentData.Max(s => s.Id) + 1;
// Add the item to the current data
currentData.Add(new Data
{
LastName = dataModel.LastName,
DateOfBirth = dataModel.DateOfBirth,
FirstName = dataModel.FirstName,
Id = dataModel.Id,
Roles = dataModel.Roles
});
// Save the data
await LocalStorage.SetItemAsync("data", currentData);
@ -31,6 +58,24 @@ public partial class Add
// highlight-next-line
NavigationManager.NavigateTo("list");
}
private void OnRoleChange(string item, object checkedValue)
{
if ((bool)checkedValue)
{
if (!dataModel.Roles.Contains(item))
{
dataModel.Roles.Add(item);
}
return;
}
if (dataModel.Roles.Contains(item))
{
dataModel.Roles.Remove(item);
}
}
}
```

@ -1,5 +1,5 @@
---
sidebar_position: 3
sidebar_position: 1
title: Effectuer des requêtes HTTP
---
@ -110,10 +110,6 @@ builder.Services.AddScoped<IDataService, DataApiService>();
Téléchargez ce [projet](/Minecraft.Crafting.Api.zip).
:::caution
Si vous avez une erreur 404 avec le téléchargement, supprimez le dernier `/` à la fin de l'url. Exemple : `.zip/` => `.zip`
:::
Décompressez le fichier dans le répertoire de votre projet, au même endroit que le répertoire du projet Blazor.
Exemple:

@ -158,6 +158,8 @@ Le code suivant :
```
```csharp title="Config.razor.cs"
private PositionOptions positionOptions;
public partial class Config
{
[Inject]

@ -13,12 +13,15 @@ Ajouter le nuget `Blazored.Modal`.
// highlight-next-line
using Blazored.Modal;
...
public static async Task Main(string[] args)
{
...
// highlight-next-line
builder.Services.AddBlazoredModal();
builder.Services.AddBlazoredModal();
...
...
}
```
### Ajouter les Imports

@ -94,17 +94,6 @@ public class DataLocalService : IDataService
public async Task<int> Count()
{
// Load data from the local storage
var currentData = await _localStorage.GetItemAsync<Item[]>("data");
// Check if data exist in the local storage
if (currentData == null)
{
// this code add in the local storage the fake data
var originalData = await _http.GetFromJsonAsync<Item[]>($"{_navigationManager.BaseUri}fake-data.json");
await _localStorage.SetItemAsync("data", originalData);
}
return (await _localStorage.GetItemAsync<Item[]>("data")).Length;
}

@ -46,7 +46,7 @@ Or dans certaines conditions nous pourrions en voir immédiatement sans devoir a
Pour pouvoir encore plus externaliser du code, comme la création de notre objet, et ne pas ralentir notre programme sil y a des instanciations longues, nous allons devoir mapper les contrats avec leurs implémentations au démarrage de lapplication.
LIOC se défini comme un conteneur qui détermine ce qui doit être instancié et retourné au client pour éviter que ce dernier appel explicitement le constructeur avec lopérateur « new ».
LIOC ce défini comme un conteneur qui détermine ce qui doit être instancié et retourné au client pour éviter que ce dernier appel explicitement le constructeur avec lopérateur « new ».
En résumé, cest un objet qui agit comme un cache pour les instances dont nous avons besoin dans diverses parties de nos applications.

@ -1,24 +1,24 @@
---
sidebar_position: 3
title: Description du composant
---
## Description
Afin de mieux comprendre notre composant complexe, nous allons en premier faire une petite description de son contenu et du comportement attendu par celui-ci.
Le but de ce composant et de permettre de tester des recettes, pour cela nous devons avoir sur la gauche un tableau contenant la liste des éléments disponible pour notre recette.
A droite nous devons trouver les emplacements qui contiendront nos éléments de recette, une fois notre recette valide, un dernier élément sera affiché sous nos emplacements avec le résulat de la recette.
Une liste en dessous contiendra l'ensemble des actions réalisées par l'utilisateur et sera géré en Javascript.
## Mockup
Pour une meilleur visualisation de notre composant, un mockup peut être réalisé afin de mieux se rendre compte du final.
Pour cela nous pouvons utiliser le site https://wireframe.cc/.
Le résulat du mockup est :
---
sidebar_position: 3
title: Description du composant
---
## Description
Afin de mieux comprendre notre composant complexe, nous allons en premier faire une petite description de son contenu et du comportement attendu par celui-ci.
Le but de ce composant et de permettre de tester des recettes, pour cela nous devons avoir sur la gauche un tableu contenant la liste des éléments disponible pour notre recette.
A droite nous devons trouver les emplacements qui contiendront nos éléments de recette, une fois notre recette valide, un dernier élément sera affiché sous nos emplacements avec le résulat de la recette.
Une liste en dessous contiendra l'ensemble des actions rélisées par l'utilisateur et sera géré en Javascript.
## Mockup
Pour une meilleur visualisation de notre composant, un mockup peut être réalisé afin de mieux se rendre compte du final.
Pour cela nous pouvons utiliser le site https://wireframe.cc/.
Le résulat du mockup est :
![Mockup](/img/blazor-component/mockup.png)

@ -96,7 +96,7 @@ public partial class CraftingItem
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"
```css title="Components/CraftingItem.razor.cs"
.item {
width: 64px;
height: 64px;

@ -78,19 +78,12 @@ public partial class Index
private List<CraftingRecipe> Recipes { get; set; } = new List<CraftingRecipe>();
protected override async Task OnAfterRenderAsync(bool firstRender)
protected override async Task OnInitializedAsync()
{
base.OnAfterRenderAsync(firstRender);
if (!firstRender)
{
return;
}
await base.OnInitializedAsync();
Items = await DataService.List(0, await DataService.Count());
Recipes = await DataService.GetRecipes();
StateHasChanged();
}
}
```

@ -65,46 +65,44 @@ Désormais notre page sera disponible à partir de l'adresse `/list` de notre si
Ouvrer le fichier `Shared/NavMenu.razor` et ajouter les lignes en surbrillances :
```cshtml title="Shared/NavMenu.razor"
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">TO_DELETE_BlazorApp30000</a>
<button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
<div class="top-row pl-4 navbar navbar-dark">
<a class="navbar-brand" href="">MyBeautifulAdmin</a>
<button class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<nav class="flex-column">
<ul class="nav flex-column">
// highlight-start
<div class="nav-item px-3">
<NavLink class="nav-link" href="list" Match="NavLinkMatch.All">
<li class="nav-item px-3">
<NavLink class="nav-link" href="list">
<span class="oi oi-list-rich" aria-hidden="true"></span> List
</NavLink>
</div>
</li>
// highlight-end
<div class="nav-item px-3">
<li class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</div>
<div class="nav-item px-3">
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</div>
<div class="nav-item px-3">
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
</NavLink>
</div>
</nav>
</li>
</ul>
</div>
@code {
private bool collapseNavMenu = true;
private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private void ToggleNavMenu()
{

@ -40,7 +40,7 @@ Pour les plus courageux (**optionnel**):
Voici les spécifications de la liste des éléments :
* La liste devra avoir une pagination.
* Le nom et l'image des éléments devront être présent.
* Un champ de recherche permettra de filtrer les éléments.
* Un champ de recherche permettra de filtrer les éléments, le filtrage devra être fait côté serveur et non par la liste.
* Il doit être possible de trier les éléments par leur noms.
## Mockup

Loading…
Cancel
Save