blazorblazor-editform

Nested EditForm In Blazor - Is This Possible?


I have two models.

  1. Customer
  2. Address

A customer can have multiple addresses. The Customer model has a List of AddressModel

public class CustomerModel
{

[Required]
public string FirstName { get; set; }

[Required]
public string LastName { get; set; }

[Required]
public List<AddressModel> Addresses { get; set; }

}


public class AddressModel
{
public int Id { get; set; }
[Required]
public string FirstLine { get; set; }
public string SecondLine { get; set; }
[Required]
public string Town { get; set; }
[Required]
public string Region { get; set; }
[Required]
public string PostalCode { get; set; }
[Required]
public string Country { get; set; }

}

I currently have an EditForm that adds a customer - that was easy.

However, using the SAME form / input screen I would like to have a "sub-EditForm" inside the main editform where I can add the addresses, then click a final submit button to submit a new customer.

The input form would look like this:

enter image description here

I have tried simply creating a new EditForm inside the main EditForm but this did not work.

I have also messed about with Context but I feel like I am perhaps looking in the wrong direction completely.

I would really appreciate it if someone would briefly explain how to have "a form within a form" in Blazor OR if they would recommend and completely different (but effective) way to capture this information.

Thank you kindly!


Solution

  • Yes, this is supported! This opens up all sorts of possibilities for sub forms that validate entry of inline dialog style interfaces for searching or adding child objects, just as you are describing here.

    There are 2 tricks to this:

    1. You cannot bind to the same Model or EditorContext.
    2. You need to name the context, by setting the Context="ArbitraryConceptualName" on the outer, or each inner EditForm

      The child content element 'ChildContent' of component 'EditForm' uses the same parameter name ('context') as enclosing child content element 'EditForm' of component 'EditForm'. Specify the parameter name like: ' to resolve the ambiguity

    The following structure for the form should work:
    NOTE: This is not a complete or tested fragment as the view was not provided in the original post

    <EditForm Model="@customer" Context="CustomerForm" OnValidSubmit="@SaveCustomer">
        <DataAnnotationsValidator />
    ...
        <div class="form-group">
            <label for="FirstName">First Name:</label>
            <InputText id="FirstName" @bind-Value="customer.FirstName" class="form-control" />
            <ValidationMessage For="@(() => customer.FirstName)" />
        </div>
    
        <div class="form-group">
            <label for="LastName">Last Name:</label>
            <InputText id="LastName" @bind-Value="customer.LastName" class="form-control" />
            <ValidationMessage For="@(() => customer.LastName)" />
        </div>
        <h4>Addresses</h4>
        <ul>
        @foreach (var a in customer.Addresses)
        {
            <li>@a.FirstLine, @a.SecondLine, @a.Town</li>
        }
        </ul>
    ...
        
        <h3>Add new address</h3>
        <EdidForm Model="@newAddress" OnValidSubmit="@AddNewAddress">
    
            <div class="form-group">
                <label for="FirstLine">First Line:</label>
                <InputText id="FirstLine" @bind-Value="newAddress.FirstLine" class="form-control" />
                <ValidationMessage For="@(() => newAddress.FirstLine)" />
            </div>
    ...
            <button type="submit" class="btn btn-outline-primary" @onclick="AddAddress">Add Address</button>
        </EditForm>
    
    ...
      <button type="submit" class="btn btn-success">Save</button>
    </EditForm>
    

    This assumes that in your code there is a placeholder for the new Address called newAddress and that your logic will add that address to the customer and reset the form:

    @code {
        private CustomerModel customer = new CustomerModel { Addresses = new List<AddressModel>() };
    
        private AddressModel newAddress = new ();
    
        private void SaveCustomer()
        {
            // Save to where ever
        }
    
        private void AddNewAddress()
        {
            customer.Addresses.Add(newAddress);
            // reset the add address form
            newAddress = new ();
        }
    
    }