Google Places Autocomplete API in Blazor server-side - InvalidValueError

Viewed 1178

I am trying to use Google's Places Autocomplete API on a Blazor server-side project but i'm getting the following errors in the console:

InvalidValueError: not an instance of HTMLInputElement
_.hd    @   js?key=AIzaSyBqbfM7v…initAutocomplete:61
_.kd    @   js?key=AIzaSyBqbfM7v…initAutocomplete:62
zu  @   js?key=AIzaSyBqbfM7v…initAutocomplete:20
initAutocomplete    @   googleAddressLookup.js:15
(anonymous) @   blazor.server.js:8
beginInvokeJSFromDotNet @   blazor.server.js:8
(anonymous) @   blazor.server.js:1
e.invokeClientMethod    @   blazor.server.js:1
e.processIncomingData   @   blazor.server.js:1
connection.onreceive    @   blazor.server.js:1
i.onmessage @   blazor.server.js:1

I can only assume that this is the blazor.server.js file blocking something somewhere as I have this working within a Razor Page outside of the Blazor environment. My JavaScript knowledge is very limited.

My JS code for Google Autocomplete (I've only made minor changes - it's mostly straight from the Google Dev Docs):

var placeSearch, autocomplete;

var componentForm = {
    street_number: 'short_name',
    route: 'long_name',
    locality: 'long_name',
    administrative_area_level_1: 'short_name',
    country: 'long_name',
    postal_code: 'short_name'
};

function initAutocomplete() {
    autocomplete = new google.maps.places.Autocomplete(
        document.getElementById('autocomplete'), { types: ['geocode'] });

    autocomplete.setFields(['address_component', 'geometry']);

    autocomplete.addListener('place_changed', fillInAddress);
}

function fillInAddress() {
    var place = autocomplete.getPlace();

    document.getElementById('autocomplete').id = 'street_number';

    for (var component in componentForm) {
        document.getElementById(component).value = '';
        document.getElementById(component).disabled = false;
    }

    document.getElementById("hidden_lat_input").value = place.geometry.location.lat();
    document.getElementById("hidden_lng_input").value = place.geometry.location.lng();

    for (var i = 0; i < place.address_components.length; i++) {
        var addressType = place.address_components[i].types[0];
        if (componentForm[addressType]) {
            var val = place.address_components[i][componentForm[addressType]];
            document.getElementById(addressType).value = val;
        }
    }

    document.getElementById('street_number').id = 'autocomplete';
}

function geolocate() {
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function (position) {
            var geolocation = {
                lat: position.coords.latitude,
                lng: position.coords.longitude
            };
            var circle = new google.maps.Circle(
                { center: geolocation, radius: position.coords.accuracy });
            autocomplete.setBounds(circle.getBounds());
        });
    }
}

The scripts are in the "_Host.cshtml" file after the blazor.js file:

<script src="_framework/blazor.server.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?key={APIKEY}&libraries=places&callback=initAutocomplete" async defer></script>
<script src="~/js/googleAddressLookup.js"></script>

Debugging in the browser shows that initAutocomplete() is being called as intended and I am using the following in my Razor Component to call geolocate(), this is also being called when intended:

private async Task GeoLocate()
{
    await Js.InvokeVoidAsync("geolocate");
}

Some of my form (the rest omitted for brevity):

                    <div id="addressInput" class="@AddressInputsCss">
                        <input @bind="Advert.Address.Latitude" hidden id="hidden_lat_input" />
                        <input @bind="Advert.Address.Longitude" hidden id="hidden_lng_input" />


                        <div class="form-group mb-4">
                            <input @bind="Advert.Address.Address1" id="autocomplete"
                                   @onfocus="(async () => await GeoLocate())" class="form-control shadow-sm" placeholder="Address *" />
                        </div>

                        <div class="form-group mb-4">
                            <input @bind="Advert.Address.Address2" class="form-control shadow-sm" id="route" placeholder="Address 2 (Optional)" />
                        </div>


                        <div class="row">
                            <div class="col-md-6">
                                <div class="form-group mb-4">
                                    <input @bind="Advert.Address.City" class="form-control shadow-sm" id="locality" placeholder="City/Town" />
                                </div>
                            </div>

                            <div class="col-md-6">
                                <div class="form-group mb-4">
                                    <input @bind="Advert.Address.State" class="form-control shadow-sm" id="administrative_area_level_1" placeholder="State" />
                                </div>
                            </div>
                        </div>

                        <div class="row">
                            <div class="col-md-6">
                                <div class="form-group mb-4">
                                    <input @bind="Advert.Address.Country" class="form-control shadow-sm" id="country" placeholder="Country *" />
                                </div>
                            </div>

                            <div class="col-md-6">
                                <div class="form-group mb-4">
                                    <input @bind="Advert.Address.PostCode" class="form-control shadow-sm" id="postal_code" placeholder="Postal Code *" />
                                </div>
                            </div>
                        </div>
                    </div>

The only difference between this and the working version I have on a Razor page is the @bind attributes to the form model instead of asp-for="..." and the need to use JSInterop which I don't think I'm doing correctly, however I can't find a solution elsewhere.

0 Answers
Related