0

I'm creating a survey generator that has the main Razor page called Survey and then from here I add the element of the survey. The component is working if I create the survey from code. Each component is using HTML tag like

@inherits ElementBase<string>
<input type="@ElementData.TextboxType.GetDescription()" 
       name="@Name" placeholder="@ElementData.PlaceHolder" 
       @bind-value="@Value" class="form-control @CssInternal @CssClass">

All the custom components are derived from a ElementBase class that implements

[CascadingParameter] internal EditContext ElementEditContext { get; set; }
[CascadingParameter] internal Survey _survey { get; set; }

private FieldIdentifier _fieldIdentifier;

[Parameter]
public T Value
{
    get
    {
        return _value;
    }

    set
    {
        _value = value;
        _survey.SetElementValue(Name, _value);
    }
}

[Parameter] public EventCallback<T> ValueChanged { get; set; }

[Parameter] public Expression<Func<T>> ValueExpression { get; set; }

protected override Task OnInitializedAsync()
{
    if (ElementEditContext != null)
    {
        // omitted for simplicity
        ElementEditContext.OnFieldChanged += FieldChanged;
        ElementEditContext.OnValidationRequested += ValidationRequested;
    }

    _survey.ElementValuesChanged += SurveyGenerator_ElementValuesChanged;

    return Task.CompletedTask;
}

In the Survey page

<CascadingValue Value="this">
    <EditForm EditContext="@editContext" OnValidSubmit="@ValidFormSubmitted">
        <table class="table">
            <tbody>
                    @for (int i = 0; i < Form.Elements.Count(); i++)
                    {
                        <tr>
                            <td>
                                <SurveyFieldGenerator 
                                     Element="@Form.Elements[i]" />
                            </td>
                        </tr>
                    }
                @if (ChildContent != null)
                {
                    @ChildContent
                }
                <tr>
                    <td colspan="2">
                        <button class="btn btn-primary" 
                                @onclick="Submit">Submit</button>
                    </td>
                </tr>
            </tbody>
        </table>
    </EditForm>
</CascadingValue>

Now, I'm trying to use some components but from a Razor page and I added this code

<Survey ShowDebug="true">
    <Survey.Components.Checkbox ElementData="@config" />
</Survey>

Here I get this error:

Unhandled exception rendering component: EditForm requires either a Model parameter, or an EditContext parameter, please provide one of these.
System.InvalidOperationException: EditForm requires either a Model parameter, or an EditContext parameter, please provide one of these.
   at Microsoft.AspNetCore.Components.Forms.EditForm.OnParametersSet()
   at Microsoft.AspNetCore.Components.ComponentBase.CallOnParametersSetAsync()
   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()

I read the document Creating Bespoke Input Components for Blazor from Scratch and the post on Stackoverflow.

First, in the OnInitialized raises immediately an error because ValueExpression is null.

protected override void OnInitialized()
{
    _fieldIdentifier = FieldIdentifier.Create(ValueExpression);
}

So, how can I change my components or only the base class in order to fix this issue?

Enrico
  • 3,592
  • 6
  • 45
  • 102

1 Answers1

1

Your code does not show the variable editContext for the Survery page and how that is created.

However, as Shaun points out, the error indicates that this variable is null when the page is first being rendered.

Try the following in Survey markup to get visibility:

@if (editContext == null)
{
    <div>editContext is null !!!!</div>
}
else
{
    <EditForm EditContext="@editContext">
        @* Form Context *@
    </EditForm>
}
Neil W
  • 7,670
  • 3
  • 28
  • 41