I have a parent component (page) that has a form with validation and also a button that when I click, I want to pass the filled form to a child component which will take the values from this form and call an api then bind to the table and show on the parent form. I would have a few different type of tables this is why I'm choosing DynamicComponents
I'm encountering couple of issues.
- At first click the GetData() method does not trigger. but it will trigger afterwards.
- The second time it works but the problem is that every time I make any change in the parent without clicking the button, the parent tries to call the child component.
Here is the code in action https://blazorrepl.telerik.com/mGPubRlU01JE0Q8q19
Also if I click submit more than 2 times, I will get an unhandled error. 'An unhandled error has occurred. Reload'
This is the parent component.
@using BlazorRepl.UserComponents
<p>
<label>
Select your Report Type please:
<TelerikDropDownList TextField="Key" ValueField="Value" Data="@ReportTypes"
@bind-Value="@SelectedOption"
DefaultText="Select Category"
Id="report">
</TelerikDropDownList>
</label>
</p>
<EditForm Model="@reportForm" OnValidSubmit="@HandleValidSubmit">
<DataAnnotationsValidator />
<div class="mb-3">
<label for="formGroupExampleInput2" class="form-label">Choose Date Range</label>
<TelerikDateRangePicker @bind-StartValue="@reportForm.StartValue"
@bind-EndValue="@reportForm.EndValue">
</TelerikDateRangePicker>
</div>
<div class="mb-3 col-3">
<label for="formGroupExampleInput2" class="form-label">Enter Item Code</label>
<TelerikTextBox @bind-Value="@reportForm.ProductId" />
<ValidationMessage For="@(() => reportForm.ProductId)" />
</div>
<div class="mb-3">
<TelerikTextBox @bind-Value="@reportForm.City" />
<ValidationMessage For="@(() => reportForm.City)" />
</div>
<div>
</div>
<TelerikButton Icon="search" OnClick="@GetData" ThemeColor="@(ThemeConstants.Button.ThemeColor.Primary)">Submit!</TelerikButton>
</EditForm>
@if (SelectedType is not null)
{
<div class="border border-primary my-1 p-1">
<DynamicComponent Type="@SelectedType" Parameters="@components[SelectedType.Name].Parameters" />
</div>
}
@code {
public ReportForm reportForm = new ReportForm();
string SelectedOption { get; set; }
private Dictionary<string, string> ReportTypes { get; set; } = new Dictionary<string, string>
{
{ "Inbound", "Inbound" },
{ "Outbound", "Outbound" }
};
private Type? SelectedType;
private string ComponentName;
public bool ValidSubmit { get; set; } = false;
private Dictionary<string, ComponentMetadata> components = new();
async Task HandleValidSubmit()
{
ValidSubmit = true;
}
async Task GetData()
{
if (SelectedOption == "Inbound" && ValidSubmit == true)
{
var component = new ComponentMetadata()
{
Name = "Inbound",
Parameters = new Dictionary<string, object>()
{{"reportForm",reportForm}}
};
SelectedType = Type.GetType($"BlazorRepl.UserComponents.{SelectedOption}");
ComponentName = component.Name;
components.Add("Inbound", component);
};
}
}
and the child component
@using BlazorRepl.UserComponents
<table >
<thead>
<tr>
<th>Product</th>
<th>Name</th>
<th>QTY</th>
</tr>
</thead>
<tbody>
<tr><td>1</td><td>Hammer</td><td>NY</td></tr>
<tr><td>2</td><td>bucket</td><td>CT</td></tr>
<tr><td>3</td><td>monitor</td><td>CA</td></tr>
<tr><td>4</td><td>laptop</td><td>NY</td></tr>
</tbody>
</table>
@code
{
private ReportForm _reportForm =new();
[Parameter]
public ReportForm reportForm {
get
{
return _reportForm;
}
set
{
if (_reportForm.Equals(value)) return;
_reportForm = value;
}
}
protected override async Task OnParametersSetAsync()
{
//api call will be here
//reportForm = _dataservice.GetData<ReportForm>();
}
}
I understand that Blazor is trying to sync the parent with the child component but how can I make it so it only gets called when I click the button?