I'm creating a library for generating form in Blazor. The logic is quite straightforward: based on a JSON, the library creates the form, using my custom component. Here a piece of the code of the Razor component called SurveyGenerator
<EditForm EditContext="@editContext" OnValidSubmit="@ValidFormSubmitted">
<table class="table">
<tbody>
@foreach (var element in Form.Elements)
{
<tr>
<td>
@switch (element.Type)
{
case "Textbox":
var el = element as PSC.Survey.Shared.Textbox;
if (!ElementValues.ContainsKey(el.Name))
ElementValues.Add(el.Name, el.Text);
<Textbox Name="@el.Name"
Placeholder="@el.PlaceHolder"
Value="@el.Text"
Title="@el.Title"
Description="@el.Description"
IsRequired="@el.IsRequired"
IsVisible="@el.IsVisible"
/>
break;
default:
<p>Unknow control</p>
break;
}
</td>
</tr>
}
<tr>
<td colspan="2">
<button class="btn btn-primary"
@onclick="Submit">Submit</button>
</td>
</tr>
</tbody>
</table>
</EditForm>
@code {
internal static readonly Dictionary<string, object> ElementValues =
new Dictionary<string, object>();
private EditContext? editContext;
}
The component Textbox
is a simple Razor component
@if(IsVisible) {
<input type="text" name="@Name" placeholder="@PlaceHolder"
@bind-value="@Value" class="form-control @CssInternal @CssClass">
}
@code {
[CascadingParameter]
private EditContext EditContext { get; set; }
private bool IsVisible;
[Parameter]
public string Value
{
get { return _value; }
set
{
if (_value != value)
{
_value = value;
SurveyGenerator.ElementValues[Name] = Value;
}
}
}
private string _value;
protected override Task OnInitializedAsync()
{
if (EditContext != null)
{
EditContext.OnFieldChanged += FieldChanged;
EditContext.OnValidationRequested += ValidationRequested;
}
return Task.CompletedTask;
}
private void FieldChanged(object sender, FieldChangedEventArgs e)
=> this.Validate(e.FieldIdentifier.FieldName);
private void ValidationRequested(object sender,
ValidationRequestedEventArgs e)
=> this.Validate();
private void Validate(string fieldname = null)
{
// validation code
}
}
So, when a component changes the property Value
, it immediately adds the value also in the variable ElementValues
in the SurveyGenerator
. When the user presses the submit button, the validation starts for all the components and it works.
Now, the problem I'm facing is that something some components have to be displayed only if another field is selected or has a particular value. Unfortunately, the EditForm
doesn't pass this information to the components. I though the event OnFieldChanged
should raise every time there is a change in any component but it is not work in this way.
For this reason, I'm looking a way to notify all the components that a value changed, like an observable collection. When the component receives the notification, it can check if it has to display itself or not, using the IsVisible
property.
Do you have any ideas or suggestions or code to share with me?