admin管理员组文章数量:1390451
I am trying to create reusable components for my MudBlazor application, to create some financial products. For example in our company, all products have a commodity (that's what you are purchasing, it's something like Oil, Gas, Electricity, ...), a currency (in which you will pay the delivery) and a delivery period (it's a period because for electricity / gas you usually purchase a given amount for a given period of time, so for example a fixed quantity per day for 1 month).
Let's badly call that CommonProperties
public class CommonProperties
{
public string? Commodity { get; set; }
public string? Currency { get; set; }
public DateTime? StartDelivery { get; set; }
public DateTime? EndDelivery { get; set; }
}
- I would like to be able to bind a CommonProperties object to my control
- I would like to be able to put this component in a form and have errors be reported to the form
- I would like to have some defaulting going on, so that for example when I select a given commodity, the currency is defaulted
I did a small snippnet
I mainly have the following code for the component
<MudSelect @bind-Value:get="Value.Commodity" @bind-Value:set="OnCommodityChanged" Label="Commodity" Required=true>
@foreach (var commo in Commodities)
{
<MudSelectItem Value="commo">@commo</MudSelectItem>
}
</MudSelect>
<MudSelect @bind-Value:get="Value.Currency" @bind-Value:set="OnCurrencyChanged" Label="Currency" Required=true>
@foreach (var currency in Currencies)
{
<MudSelectItem Value="currency">@currency</MudSelectItem>
}
</MudSelect>
<MudTextField T="DateTime?" Format="yyyy-MM-dd" @bind-Value:get="Value.StartDelivery" @bind-Value:set="OnDeliveryStartChanged" Label="StartDate" InputType="InputType.Date" Required=true/>
And the following code:
private readonly string[] Commodities = [ "Oil", "Gas", "Elec" ];
private readonly string[] Currencies = [ "EUR", "USD" ];
[Parameter]
public CommonProperties Value { get; set; } = new();
[Parameter]
public EventCallback<CommonProperties> ValueChanged { get; set; }
private async Task OnCommodityChanged(string? commodity)
{
Value.Commodity = commodity;
var defaultCurrency = commodity is "Oil" ? "EUR" : "USD";
Value.Currency = defaultCurrency;
await ValueChanged.InvokeAsync(Value);
}
private async Task OnCurrencyChanged(string? currency)
{
Value.Currency = currency;
await ValueChanged.InvokeAsync(Value);
}
private async Task OnDeliveryStartChanged(DateTime? start)
{
Value.StartDelivery = start;
await ValueChanged.InvokeAsync(Value);
}
- Do I need to manually implement all change callbacks, set the object, invoke the handler, is there a way like just binding
bind-Value:set=Value.Currency
and that everything works fine in a parent component if I bind theCurrency
as an input in another component, will the changes be tracked although it's a nested property (I don't understand how the change pipeline works) - On the code snippnet, if I press Validate to trigger validation with everything empty, if I then fill in the commodity, in will fill in the currency, the commodity will not be in error anymore but the currency will even if it is required and filled in. I guess I have to do something with the EditContext, but I don't understand how it works with nested properties.
Do you have some tips on how to design such components / have a good validation flow ?
Thank you
I am trying to create reusable components for my MudBlazor application, to create some financial products. For example in our company, all products have a commodity (that's what you are purchasing, it's something like Oil, Gas, Electricity, ...), a currency (in which you will pay the delivery) and a delivery period (it's a period because for electricity / gas you usually purchase a given amount for a given period of time, so for example a fixed quantity per day for 1 month).
Let's badly call that CommonProperties
public class CommonProperties
{
public string? Commodity { get; set; }
public string? Currency { get; set; }
public DateTime? StartDelivery { get; set; }
public DateTime? EndDelivery { get; set; }
}
- I would like to be able to bind a CommonProperties object to my control
- I would like to be able to put this component in a form and have errors be reported to the form
- I would like to have some defaulting going on, so that for example when I select a given commodity, the currency is defaulted
I did a small snippnet https://try.mudblazor/snippet/mOGfknFQoIDmgcYy
I mainly have the following code for the component
<MudSelect @bind-Value:get="Value.Commodity" @bind-Value:set="OnCommodityChanged" Label="Commodity" Required=true>
@foreach (var commo in Commodities)
{
<MudSelectItem Value="commo">@commo</MudSelectItem>
}
</MudSelect>
<MudSelect @bind-Value:get="Value.Currency" @bind-Value:set="OnCurrencyChanged" Label="Currency" Required=true>
@foreach (var currency in Currencies)
{
<MudSelectItem Value="currency">@currency</MudSelectItem>
}
</MudSelect>
<MudTextField T="DateTime?" Format="yyyy-MM-dd" @bind-Value:get="Value.StartDelivery" @bind-Value:set="OnDeliveryStartChanged" Label="StartDate" InputType="InputType.Date" Required=true/>
And the following code:
private readonly string[] Commodities = [ "Oil", "Gas", "Elec" ];
private readonly string[] Currencies = [ "EUR", "USD" ];
[Parameter]
public CommonProperties Value { get; set; } = new();
[Parameter]
public EventCallback<CommonProperties> ValueChanged { get; set; }
private async Task OnCommodityChanged(string? commodity)
{
Value.Commodity = commodity;
var defaultCurrency = commodity is "Oil" ? "EUR" : "USD";
Value.Currency = defaultCurrency;
await ValueChanged.InvokeAsync(Value);
}
private async Task OnCurrencyChanged(string? currency)
{
Value.Currency = currency;
await ValueChanged.InvokeAsync(Value);
}
private async Task OnDeliveryStartChanged(DateTime? start)
{
Value.StartDelivery = start;
await ValueChanged.InvokeAsync(Value);
}
- Do I need to manually implement all change callbacks, set the object, invoke the handler, is there a way like just binding
bind-Value:set=Value.Currency
and that everything works fine in a parent component if I bind theCurrency
as an input in another component, will the changes be tracked although it's a nested property (I don't understand how the change pipeline works) - On the code snippnet, if I press Validate to trigger validation with everything empty, if I then fill in the commodity, in will fill in the currency, the commodity will not be in error anymore but the currency will even if it is required and filled in. I guess I have to do something with the EditContext, but I don't understand how it works with nested properties.
Do you have some tips on how to design such components / have a good validation flow ?
Thank you
Share Improve this question edited Mar 13 at 1:58 Qiang Fu 9,4071 gold badge6 silver badges16 bronze badges asked Mar 12 at 12:41 Victor BurckelVictor Burckel 2131 silver badge7 bronze badges1 Answer
Reset to default 1For the second issue, you could use StateHasChanged
before revalidation then the function will work normally. And
Value.Currency = defaultCurrency;
StateHasChanged(); // Update the value state
form?.Validate(); // revalidate
await ValueChanged.InvokeAsync(Value);
From my understanding you want a double way binding from the child component to parent component. Then you could try following code to use @bind-Value:after
instead.
Child.razor
<MudPaper Class="pa-4">
<MudForm @ref="form" @bind-IsValid="@success" @bind-Errors="@errors" EditContext="@editContext">
<div class="d-flex">
<MudSelect @bind-Value="Value.Commodity" @bind-Value:after="OnCommodityChanged" Label="Commodity" Required=true>
@foreach (var commo in Commodities)
{
<MudSelectItem Value="commo">@commo</MudSelectItem>
}
</MudSelect>
<MudSelect @bind-Value="Value.Currency" @bind-Value:after="OnCurrencyChanged" Label="Currency" Required=true>
@foreach (var currency in Currencies)
{
<MudSelectItem Value="currency">@currency</MudSelectItem>
}
</MudSelect>
<MudTextField T="DateTime?" Format="yyyy-MM-dd" @bind-Value:get="Value.StartDelivery" @bind-Value:set="OnDeliveryStartChanged" Label="StartDate" InputType="InputType.Date" Required=true />
</div>
<div class="d-flex">
<MudButton Variant="Variant.Filled" Color="Color.Primary" Disabled="@(!success)" Class="ml-auto">Register</MudButton>
</div>
</MudForm>
</MudPaper>
<MudPaper Class="pa-4 mt-4">
<MudButton Variant="Variant.Filled" Color="Color.Primary" DropShadow="false" OnClick="@(()=>form.Validate())">Validate</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Secondary" DropShadow="false" OnClick="@(()=>form.ResetAsync())" Class="mx-2">Reset</MudButton>
<MudButton Variant="Variant.Filled" DropShadow="false" OnClick="@(()=>form.ResetValidation())">Reset Validation</MudButton>
</MudPaper>
@code {
public class CommonProperties
{
public string? Commodity { get; set; }
public string? Currency { get; set; }
public DateTime? StartDelivery { get; set; }
public DateTime? EndDelivery { get; set; }
}
private readonly string[] Commodities = ["Oil", "Gas", "Elec"];
private readonly string[] Currencies = ["EUR", "USD"];
[Parameter]
public CommonProperties Value { get; set; } = new();
[Parameter]
public EventCallback<CommonProperties> ValueChanged { get; set; }
private EditContext editContext;
protected override void OnInitialized()
{
editContext = new EditContext(Value);
}
private async Task OnCommodityChanged()
{
var defaultCurrency = Value.Commodity is "Oil" ? "EUR" : "USD";
Value.Currency = defaultCurrency;
StateHasChanged(); // Update the value state before revalidate
form?.Validate(); // revalidate
await ValueChanged.InvokeAsync(Value);
}
private async Task OnCurrencyChanged()
{
await ValueChanged.InvokeAsync(Value);
}
private async Task OnDeliveryStartChanged(DateTime? start)
{
Value.StartDelivery = start;
await ValueChanged.InvokeAsync(Value);
}
bool success;
string[] errors = [];
MudForm form;
}
Parent.razor
<Child @bind-Value="ParentValue"></Child>
Parent Commodity: @ParentValue.Commodity
<br />
Parent Currency: @ParentValue.Currency
@code{
CommonProperties ParentValue = new();
}
本文标签:
版权声明:本文标题:asp.net core - MudBlazor reusable component for editing complex objects with field defaulting from other fields - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744752282a2623250.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论