TelerikForm that includes an Address component

1 Answer 53 Views
Form
scott
Top achievements
Rank 1
scott asked on 26 Aug 2024, 05:31 PM | edited on 26 Aug 2024, 05:31 PM

Hi Everyone,

I am trying to include a component in my TelerikForm which will contain a <FormGroup>, <FormItems> and all the bits for a mailing address.  This has been giving me some grief and I would love some help.  Here's what I have: 

Here's the outside component:

@page "/agencies/new"
@using kpow.interfaces.Services.Agencies
@using kpow.Ui.Components
@inject IAgencies AgencyService

<TelerikForm EditContext="formContext">
    <FormValidation>
        <DataAnnotationsValidator></DataAnnotationsValidator>
        <TelerikValidationSummary />
    </FormValidation>
    <FormItems>
        <FormItem Field="@nameof(Agency.Name)" LabelText="Name" />
        <FormItem Field="@nameof(Agency.AgencyType)" LabelText="Agency Type" />

        <AddressSubForm
            Address="@Agency.Address"
            SetAddress="address => Agency.Address = address"/>
    </FormItems>
</TelerikForm>
@code {
    private Agency Agency { get; } = new() { Address = new Address() };
    EditContext formContext { get; set; }

    protected override void OnInitialized()
    {
        formContext = new EditContext(Agency);
        base.OnInitialized();
    }
}

 

Here's the AddressSubForm Component:

 

@inject interfaces.Services.Ports.ICountries CountryService
<FormGroup LabelText="Address">
  <FormItem Field="@nameof(Address.ToLine)" LabelText="ToLine" ></FormItem>
    <FormItem Field="@nameof(Address.Street1)" LabelText="Street"></FormItem>
    <FormItem Field="@nameof(Address.Street2)" LabelText="Street 2"></FormItem>
    <FormItem Field="@nameof(Address.City)" LabelText="City"></FormItem>
    <FormItem Field="@nameof(Address.PostalCode)" LabelText="Postal Code"></FormItem>
@if (ShowRegions == true)
{
    <FormItem Field="@nameof(RegionId)" LabelText="Region">
        <Template>
            <TelerikDropDownList Data="@regions"
                                 TextField="Name"
                                 ValueField="Id"
                                 @bind-Value="RegionId">
            </TelerikDropDownList>
        </Template>
    </FormItem>
}
    <FormItem Field="@nameof(CountryId)" LabelText="Country">
        <Template>
            <TelerikDropDownList Id="cbCountries"
                                 TextField="Name"
                                 ValueField="Id"
                                 Data="@countries"
                                 OnChange="CountryChanged"
                                 @bind-Value="CountryId">
            </TelerikDropDownList>
        </Template>
    </FormItem>
</FormGroup>

@code {
    [Parameter] public Address Address { get; set; } = new Address();
    [Parameter] public Func<Address, Address>? SetAddress { get; set; }

    private IEnumerable<Country>? countries { get; set; }
    private IEnumerable<Region>? regions { get; set; }
    private bool ShowRegions { get; set; } = false;

    private string ToLine { get; set; } = string.Empty;
    private string Street1 { get; set; } = string.Empty;
    private string? Street2 { get; set; } = string.Empty;
    private string City { get; set; } = string.Empty;
    private int? RegionId { get; set; } = null;
    private string PostalCode { get; set; } = string.Empty;
    private int? CountryId { get; set; } = null;

    protected override async Task OnInitializedAsync()
    {
        ToLine = Address.ToLine;
        Street1 = Address.Street1;
        Street2 = Address.Street2;
        City = Address.City;
        RegionId = Address.RegionId;
        PostalCode = Address.PostalCode;
        CountryId = Address.CountryId;

        countries = await CountryService.GetAll();
    }



    private async Task CountryChanged(object value)
    {
        CountryId = (int)value; // Ensure CountryId is updated
        Address = SetAddress(Address with { CountryId = (int)value, RegionId = null });

        switch (CountryId)
        {
            case 185: //usa
            case 32:  //canada
                {
                    regions = await CountryService.GetRegions(CountryId.Value);
                    ShowRegions = true;

                    break;
                }
            default:
                {
                    ShowRegions = false;

                    break;
                }
        }

    }

    private void RegionChanged(object value)
    {
        Address = SetAddress(Address with { RegionId = (int)value });
    }

}

 

When this runs, I can see the rendered labels in the right place for the Address, but the countries drop down is not filled even though the data is present in the OnInitializedAsync when it calls await CountryService.GetAll();   Also, none of the form fields in Address render - only the label.  There is an error in console per field in the Address component that is not using a template: 

crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Value cannot be null. (Parameter 'For')
System.ArgumentNullException: Value cannot be null. (Parameter 'For')
   at Telerik.Blazor.Components.Common.BaseComponent.ThrowIfParameterIsNull(Object argumentValue, String argumentName)
   at Telerik.Blazor.Components.Validation.ValidationMessageBase`1[[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].OnParametersSet()
   at Microsoft.AspNetCore.Components.ComponentBase.CallOnParametersSetAsync()
   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()

I'm looking forward to hearing your ideas!  Thanks!

-scott

 

                                      

1 Answer, 1 is accepted

Sort by
0
Nadezhda Tacheva
Telerik team
answered on 28 Aug 2024, 01:06 PM

Hi Scott,

I will address the relevant issues I see separately for more clarity:

Form with custom component - structure

To add a custom component with additional fields in the Form you will need a bit different structure. You can use the following article for reference: Use Form Items inside Custom Components.

Value cannot be null. (Parameter 'For') error

This error usually means that the Field is not set correctly. For example, it looks like all address form items use nested fields, so the Fields should be Field="Address.RegionId" and not just Field="RegionId". Similar to how the binding to nested fields is handled in the Grid here.

A FormItem can't have non-existent / invalid Field and no Template at the same time.

===

I hope the above information will help you move forward with the configuration on your end.

Regards,
Nadezhda Tacheva
Progress Telerik

Do you have a stake in the designеr-developer collaboration process? If so, take our survey to share your perspective and become part of this global research. You’ll be among the first to know once the results are out.
-> Start The State of Designer-Developer Collaboration Survey 2024

Tags
Form
Asked by
scott
Top achievements
Rank 1
Answers by
Nadezhda Tacheva
Telerik team
Share this question
or