Hopefully someone can advise me how to get out of this corner I've coded myself into! I'm pretty new to Blazor and have never created a dynamically generated form before. I THOUGHT I was on the right track, but maybe not. I need to add as many of the child component (DynamicStep.razor) to an editform as the user requires. I can add them to the parent page without issue. I can also get the values from the controls...the problem is I just don't have clue which control each of the values came from.
If I'm on the wrong path, can someone point me in the right direction? Any help would be enormously appreciated!
DynamicStep.razor (Child Component):
<div class="col-lg-3">
<label for="@Id" class="fw-bold">@Id</label>
<div class="input-group">
<select id="@Id" @bind:get="StepValue" @bind:set="SetValue!">
<option selected value="0">N/A</option>
<option value="1">Pass</option>
<option value="2">Fail</option>
<option value="3">In Progress</option>
</select>
</div>
</div>
@code {
[Parameter] public string? Id { get; set; }
[Parameter] public EventCallback<string> HandleNewStepEvent { get; set; }
[Parameter] public string? StepValue { get; set; }
private async Task SetValue(string newValue)
{
if (StepValue != newValue)
{
StepValue = newValue;
await HandleNewStepEvent.InvokeAsync(newValue);
}
}
}
Parent:
<div class="row">
<div class="col-lg-12">
<EditForm Model="@addJobStep" OnValidSubmit="AddJobStepControl" FormName="frmAddJobStep">
<DataAnnotationsValidator />
<div class="container-fluid border border-1 rounded p-3" style="background-color:lightgray;">
<div class="row">
<div class="col-lg-3">
<label for="stepOrder">Step Order</label>
<InputSelect id="stepName" @bind-Value="addJobStep.StepName" class="form-control form-control-sm">
<option selected disabled value="">Select a Step</option>
@if (stepTitles != null)
{
@foreach (var val in stepTitles!)
{
<option value="@val.Title">@val.Title</option>
}
}
</InputSelect>
<ValidationMessage For="@(() => addJobStep.StepName)" />
</div>
<div class="col-lg-3">
<label for="stepOrder">Step Order</label>
<InputNumber id="stepOrder" @bind-Value="addJobStep.StepOrder" class="form-control form-control-sm" />
<ValidationMessage For="@(() => addJobStep.StepOrder)" />
</div>
</div>
<div class="row pt-2">
<div class="input-group">
<div class="pe-1">
<button type="submit" class="btn btn-sm btn-primary">
<span class="bi bi-plus-circle" aria-hidden="false"></span> Add
</button>
</div>
<div class="pe-1">
<button type="button" class="btn btn-sm btn-warning" @onclick="ClearJobStep">
<span class="bi bi-x-lg" aria-hidden="false"></span> Clear
</button>
</div>
</div>
</div>
</div>
</EditForm>
</div>
</div>
<div class="row">
<div class="col-lg-12 mt-2">
@* I have a quickgrid here that displays all the generated controls where I can edit or delete them. *@
</div>
</div>
<div class="row">
<div class="col-lg-12">
<EditForm Model="@addDeliverable" OnValidSubmit="AddDeliverable">
<DataAnnotationsValidator />
<div class="container-fluid border border-1 rounded p-3" style="background-color:lightgray;">
<div class="row">
<div class="col-lg-4">
<label for="prod">Prod/RMA</label>
<InputText id="prod" @bind-Value="addDeliverable.ProdRMA" class="form-control form-control-sm" />
<ValidationMessage For="@(() => addDeliverable.ProdRMA)" />
</div>
<div class="col-lg-4">
<label for="serialnumber">Serial#</label>
<InputText id="serialnumber" @bind-Value="addDeliverable.SerialNumber" class="form-control form-control-sm" />
<ValidationMessage For="@(() => addDeliverable.SerialNumber)" />
</div>
<div class="row">
@if (jobStepList != null)
{
<div class="row">
@foreach (var step in jobStepList)
{
<DynamicStep @key="@step.JobStepId" Id="@step.StepName" HandleNewStepEvent="HandleNewStepEvent"></DynamicStep>
}
</div>
}
</div>
<div class="col-lg-3">
<div class="input-group mt-4">
<div class="pe-1">
<button type="submit" class="btn btn-sm btn-primary">
<span class="bi bi-plus-circle" aria-hidden="false"></span> Add
</button>
</div>
<div class="pe-1">
<button type="button" class="btn btn-sm btn-warning" @onclick="ClearDeliverable">
<span class="bi bi-x-lg" aria-hidden="false"></span> Clear
</button>
</div>
</div>
</div>
</div>
</div>
</EditForm>
</div>
</div>
@code{
private List<StepTitle>? stepTitles;
private string stepId;
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
dbContext = DbContextFactory.CreateDbContext();
await LoadStepOptions();
await LoadJobStepControls();
}
private async Task LoadStepOptions()
{
//This holds values like "Mechanical", "Final Prep", "Final Inspection", etc...
stepTitles = await dbContext.StepTitles.ToListAsync();
}
private void HandleNewStepEvent(string extraStep)
{
//not sure what to do here since I can't tell which child control the value is coming from
}
private async Task AddJobStepControl()
{
hideStepMessage = true;
if (jobStepList != null && jobStepList.Count > 0)
{
bool alreadyExists = jobStepList.Any(x => x.StepName == addJobStep.StepName!.ToString());
if (alreadyExists)
{
hideStepMessage = false;
return;
}
}
using var context = DbContextFactory.CreateDbContext();
addJobStep.JobId = JobId;
await context.JobSteps.AddAsync(addJobStep);
await context.SaveChangesAsync();
await LoadJobStepControls();
addJobStep = new();
}
private async Task LoadJobStepControls()
{
jobStepList = await dbContext.JobSteps.Where(x => x.JobId == JobId).ToListAsync();
}
}