0

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?

Enrico
  • 3,592
  • 6
  • 45
  • 102
  • ` I though the event OnFieldChanged should raise every time there is a change in any component but it is not work in this way.``EditContext.OnFieldChanged` is changed in `OnInitializedAsync`.And it is invoked when the component is initialized.You can refer to the official [doc](https://learn.microsoft.com/en-us/aspnet/core/blazor/components/lifecycle?view=aspnetcore-6.0). – Yiyi You Aug 18 '22 at 09:11
  • Build yourself a view Service that contains all your data and events to notify changes. Then each component injects the service and registers for the necessary events. There's a answer here that isn't a great fit to your code, but shows how to do the service and wiring. https://stackoverflow.com/questions/69558006/how-can-i-trigger-refresh-my-main-razor-page-from-all-of-its-sub-components-wit/69562295#69562295 – MrC aka Shaun Curtis Aug 18 '22 at 12:11

0 Answers0