Autocompletado de direcciones con Google Maps (Blazor)

Ejemplo muestra cómo implementar un formulario de dirección en una aplicación Blazor

Este ejemplo muestra cómo implementar un formulario de dirección en una aplicación Blazor utilizando la API de Google Maps para autocompletado. Se utiliza el componente RadzenTextBox y el modelo de datos Dinaup.AddressModel para capturar los datos introducidos por el usuario.

1

Requisitos

Antes de utilizar este ejemplo, asegúrate cumplir los siguiente requisitos:

  • El paquete NuGet Dinaup, que incluye el modelo AddressModel.

  • El paquete NuGet Radzen.Blazor para los componentes de formulario.

  • Una clave válida de la API de Google Maps con el servicio Places habilitado.

2

Carga de la biblioteca de Google Maps

Agregar la siguiente línea dentro de la sección <head> del archivo HTML principal (_Host.cshtml o index.html):

<script 
  src="https://maps.googleapis.com/maps/api/js?key={APIKEY}&libraries=places&language=es" 
  onerror="window.MapsApiError = true"></script>

Reemplaza {APIKEY} por tu clave de API de Google Maps.

3

Funciones JavaScript necesarias


function googleMapsIsAvailable() {
    const script = document.querySelector('#maps-api');
    const cargado = !!(window.google && google.maps && google.maps.places);

    if (!cargado && script) {
        console.warn("Google Maps cargado pero Places no disponible — posible error de referrer o clave.");
        return false;
    }

    return cargado;
}

function initAutocomplete(uniqueIdSuffix, dotNetHelper) {

    if (!googleMapsIsAvailable()) { return; }



    const input = document.getElementById('autocomplete_' + uniqueIdSuffix);
    const options = { types: ['geocode'],  };

    const autocomplete = new google.maps.places.Autocomplete(input, options);

    autocomplete.addListener('place_changed', function () {

        const place = autocomplete.getPlace();
        if (place.address_components) {
            const address = {
                city: '',
                province: '',
                postalCode: '',
                country: '',
                countryCode: ''
            };

            place.address_components.forEach(component => {
                const types = component.types;
                if (types.includes('route')) {
                } else if (types.includes('locality')) {
                    address.city = component.long_name;
                } else if (types.includes('administrative_area_level_2')) {
                    address.province = component.long_name;
                } else if (types.includes('postal_code')) {
                    address.postalCode = component.long_name;
                } else if (types.includes('country')) {
                    address.country = component.long_name;
                    address.countryCode = component.short_name;

                }
            });

            dotNetHelper.invokeMethodAsync('SetAddress', address);
        }
    });
}

4

Componente Blazor

Este fragmento usa componentes de Radzen y enlaza automáticamente con Dinaup.AddressModel.

@inject IJSRuntime JS

<RadzenFormField class=@("w-100 m-2 " + (AddressData.AddressLine1.IsEmpty() ? "obli" : "")) Text="Dirección" Variant="Variant.Flat">
	<RadzenTextBox Disabled=@Disabled id="@($"autocomplete_{uniqueIdSuffix}")" @bind-Value="AddressData.AddressLine1" Style="width: 100%;" @bind-Value:after=@onChange />
</RadzenFormField>

<RadzenFormField class="w-100 m-2" Text="Dirección 2" Variant="Variant.Flat">
	<RadzenTextBox Disabled=@Disabled Placeholder="Piso, Planta..." id="@($"direccion2_{uniqueIdSuffix}")" @bind-Value="AddressData.AddressLine2" Style="width: 100%;" @bind-Value:after=@onChange />
</RadzenFormField>


<div class="d-flex gap-2">
	<RadzenFormField class=@("w-50 m-2 " + (AddressData.City.IsEmpty() ? "obli" : "")) Text="Municipio" Variant="Variant.Flat">
		<RadzenTextBox Disabled=@Disabled id="@($"city_{uniqueIdSuffix}")" @bind-Value="AddressData.City" Style="width: 100%;" @bind-Value:after=@onChange />
	</RadzenFormField>
	<RadzenFormField class=@("w-25 m-2 " + (AddressData.Province.IsEmpty() ? "obli" : "")) Text="Provincia" Variant="Variant.Flat">
		<RadzenTextBox Disabled=@Disabled id="@($"province_{uniqueIdSuffix}")" @bind-Value="AddressData.Province" Style="width: 100%;" @bind-Value:after=@onChange />
	</RadzenFormField>
	<RadzenFormField class=@("w-25 m-2 " + (AddressData.PostalCode.IsEmpty() ? "obli" : "")) Text="Código Postal" Variant="Variant.Flat">
		<RadzenTextBox Disabled=@Disabled id="@($"postalCode_{uniqueIdSuffix}")" @bind-Value="AddressData.PostalCode" Style="width: 100%;" @bind-Value:after=@onChange />
	</RadzenFormField>
</div>

<div class="d-flex gap-2">
	<RadzenFormField class=@("w-50 m-2 " + (AddressData.Country.IsEmpty() ? "obli" : "")) Text="País" Variant="Variant.Flat">
		<RadzenTextBox Disabled=@Disabled id="@($"country_{uniqueIdSuffix}")" @bind-Value="AddressData.Country" Style="width: 100%;" @bind-Value:after=@onChange />
	</RadzenFormField>
	@if (WithCountryCode)
	{
		<RadzenFormField class=@("w-50 m-2 " + (AddressData.CountryCode.IsEmpty() ? "obli" : "")) Text="Código País" Variant="Variant.Flat">
			<RadzenTextBox Disabled=@Disabled id="@($"countrycode_{uniqueIdSuffix}")" @bind-Value="AddressData.CountryCode" Style="width: 100%;" @bind-Value:after=@onChange />
		</RadzenFormField>
	}
</div>

@code {

	private string uniqueIdSuffix = Guid.NewGuid().ToString("N");

	[Parameter]
	public bool Disabled { get; set; }
	[Parameter]
	public bool WithCountryCode { get; set; } = true;
	[Parameter]
	public EventCallback OnChange { get; set; }
	[Parameter]
	public Dinaup.AddressModel AddressData { get; set; }





	bool prevenChange = false;
	void onChange()
	{

		if (AddressData.CountryCode.IsNotEmpty())
			AddressData.CountryCode = AddressData.CountryCode.ToUpper();

		if (prevenChange == false)
			OnChange.InvokeAsync();
	}



	protected override async Task OnAfterRenderAsync(bool firstRender)
	{
		await base.OnAfterRenderAsync(firstRender);
		if (firstRender)
			await JS.InvokeVoidAsync("initAutocomplete", uniqueIdSuffix, DotNetObjectReference.Create(this));

	}


	[JSInvokable]
	public void SetAddress(AddressDTO address)
	{

		if (Disabled) return;
		prevenChange = true;
		AddressData.City = Dinaup.ValidationUtils.NormalizeLocationName(address.City);
		AddressData.Province = address.Province;
		AddressData.PostalCode = address.PostalCode;
		AddressData.Country = address.Country;
		AddressData.CountryCode = address.countryCode;
		StateHasChanged();
		prevenChange = false;
		onChange();

	}

	public class AddressDTO
	{
		public string Address { get; set; }
		public string City { get; set; }
		public string Province { get; set; }
		public string PostalCode { get; set; }
		public string Country { get; set; }
		public string countryCode { get; set; }
	}

}

Última actualización