Sajeev C
Sajeev C

Reputation: 1538

InvalidValueError: not an instance of HTMLInputElement

FYI, I'm not a JavaScript Ninja but felt like I'll become one when I did a lot of things based on Google Maps recently.

I implemented a map. User can search for google places and place a marker for it. there's a text box for that. Or user can click on the map to place a marker to the place he's looking for or drag the marker.

Code remains the same. Design changed. Input field's id and name also same. No change to JS code. But this thing ain't working.

Here's the website

Google map is producing an error.

 InvalidValueError: not an instance of HTMLInputElement

I tried solution given here But error still remains.

What could be the possible reason?

Here's the code:

        var map;
        var marker;
        var latLngC;

        function initialize() 
        {
            latLngC = new google.maps.LatLng(14.5800, 121.0000);
            var mapOptions = {
        center: latLngC,
        zoom: 12,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        };

            map = new google.maps.Map(document.getElementById('source_map'),
        mapOptions);

        var marker = new google.maps.Marker({
                position: latLngC,
                map: map,
                draggable: true
            });

            google.maps.event.addListener(marker, 'dragend', function (x) 
            {
            document.getElementById('src_lat').value = x.latLng.lat();
            document.getElementById('src_long').value = x.latLng.lng();
            document.getElementById('pickup_location').innerHTML = x.latLng.lat()+' , '+x.latLng.lng();
                var geocoder = new google.maps.Geocoder;
                var infowindow = new google.maps.InfoWindow;                
            geocodeLatLng(geocoder, map, infowindow,x.latLng.lat(),x.latLng.lng(),'source_point');
            }); 

            //Get coordinates,address Upon clicking a location in map (Source Map)
            //By Sajeev
            google.maps.event.addListener(map, 'click', function(x) 
            {
            document.getElementById('src_lat').value = x.latLng.lat();
            document.getElementById('src_long').value = x.latLng.lng();
            document.getElementById('pickup_location').innerHTML = x.latLng.lat()+' , '+x.latLng.lng();
                var geocoder = new google.maps.Geocoder;
                var infowindow = new google.maps.InfoWindow;                
            geocodeLatLng(geocoder, map, infowindow,x.latLng.lat(),x.latLng.lng(),'source_point');
            });

        //Add marker upon clicking on map
            //google.maps.event.addDomListener(map, 'click', addMarker);
            google.maps.event.addDomListener(map, 'click', function() { addMarker(map); }); 



        var places1 = new google.maps.places.Autocomplete(document.getElementById('source_point'));
        google.maps.event.addListener(places1, 'place_changed', function () {
            var place1 = places1.getPlace();

            var src_addr = place1.formatted_address;
            var src_lat = place1.geometry.location.lat();
            var src_long = place1.geometry.location.lng();

            var mesg1 = "Address: " + src_addr;
            mesg1 += "\nLatitude: " + src_lat;
            mesg1 += "\nLongitude: " + src_long;
            //alert(mesg1);

                 document.getElementById('src_lat').value = src_lat;
            document.getElementById('src_long').value = src_long;
            document.getElementById('pickup_location').innerHTML = src_lat+' , '+src_long;                 
        });
        //Add marker upon place change
        //google.maps.event.addDomListener(places1, 'place_changed', addMarker);            
            google.maps.event.addDomListener(places1, 'place_changed', function() { addMarker(map); }); 

        }
        google.maps.event.addDomListener(window,'resize',initialize);
        google.maps.event.addDomListener(window, 'load', initialize); 

My HTML code looks like this:

   <form role="form" id="frm_source" name="frm_source" method="POST" action="index_action.php">

        <div class="form-group">
            <label for="source_point"><h2>Pickup Address</h2></label>
            <textarea type="text" id="source_point" name="source_point"  class="form-control" placeholder="Enter your pick up address here"></textarea>
        </div>

        <div class="form-group">
            <label for="pickup_location"><h3>GPS Cordinates</h3></label>
            <hr>
            <p id="pickup_location"></p>
        </div>

        <div class="form-group">
            <input type="hidden" id="src_lat" name="src_lat" placeholder="latitude" >
            <input type="hidden" id="src_long" name="src_long" placeholder="longitude" >
        </div>

    <input type="submit" name="submit" id="submit" class="btn btn-primary" value="Next to enter destination address" />
    </form>

Google Map

<div id="source_map"></div>

Upvotes: 33

Views: 100675

Answers (12)

user19745159
user19745159

Reputation:

Svelte users

await tick() is the answer to: "was causing the Google Maps script to execute asynchronously while the rest of the page continued parsing"

So inside your loadGooglePlacesLibrary method, before your autocomplete = new google.maps.places.Autocomplete(inputField, options), await tick()

  function init(placesApiKey: string) {
    loadGooglePlacesLibrary(placesApiKey, async () => {
      await tick()

      // @ts-ignore
      autocomplete = new google.maps.places.Autocomplete(inputField, options)

Upvotes: 0

Haider Ali
Haider Ali

Reputation: 13

I know I am answering this question late but this might be helpful for someone:

Instead of Using Jquery to get element:

    var autocomplete = new google.maps.places.Autocomplete($("#Location"));

Do something Like this & it works for me:

    var input = document.getElementById('Location');
    var autocomplete = new google.maps.places.Autocomplete(input);

Upvotes: 0

fjsj
fjsj

Reputation: 11260

InvalidValueError also happens as well when you try to configure the Google Places Autocomplete inside an iframe. If you do it from the parent DOM, you'll get this error because:

if your app is one of those rare ones that use multiple windows with cross-window DOM inspection (or similar), window.HTMLInputElement === otherWindow.HTMLInputElement will be false, thus the instanceof operator may also unexpectedly return false. Applies to iframes and popup windows as well. In those cases, checking tagName can work, as other answers already mentioned. – John Weisz

The solution is twofold:

  1. Inject Google script into the iframe.
  2. Grab the iframe window object with iframe.contentWindow and call google.maps.places.Autocomplete() from it.

Here's an example:

var GOOGLE_API_KEY = 'fill-me';
var AUTOCOMPLETE_CONFIG = { /* fill-me */  };
function handlePlaceSelect() { /* fill-me */  }

var iframeWindow = iframe.contentWindow;
var iframeDocument = iframe.contentDocument;

var googleScript = document.createElement("script");
googleScript.type = "text/javascript";
googleScript.src = "https://maps.googleapis.com/maps/api/js?key=" + GOOGLE_API_KEY + "&libraries=places";
iframeDocument.body.appendChild(googleScript);

googleScript.addEventListener('load', function() {
  autoComplete = new iframeWindow.google.maps.places.Autocomplete(addressInput, AUTOCOMPLETE_CONFIG);
  autoComplete.addListener("place_changed", function () {
    handlePlaceSelect();
  });
});

Upvotes: 0

Dương Mạnh Đăng
Dương Mạnh Đăng

Reputation: 21

in my case, error's reason is google.maps.ControlPosition run more than one time. My google map is shown in modal. In the first time I opened modal, everything is ok but the next time, this error show up. My solution: Init the map just one time.

constructor(props) {
        super(props);
        this.state = {
            lat: null,
            lng: null,
            visible: false,
            inited: false
        };
        this.initMap = this.initMap.bind(this);
        this.setModalVisible = this.setModalVisible.bind(this);
    }

    setModalVisible(status) {
        if (!this.state.inited) {
            //Khi chưa init map lần nào (chưa từng mở modal)
            this.setState(
                {
                    visible: true,
                    inited: true
                },
                () => {
                    this.initMap();
                }
            );
        } else {
            // Khi đã init, đóng/mở modal mà k cần init lại
            this.setState({
                visible: status
            });
        }
    }
    initMap() {
        if (this.state.visible) {
            let map = new google.maps.Map(document.getElementById("map"), {
                center: { lat: 21.0277644, lng: 105.8341598 },
                zoom: 10
            });
            const card = document.getElementById("pac-card");
            const input = document.getElementById("pac-input");
            const options = {
                fields: ["formatted_address", "geometry", "name"],
                origin: map.getCenter(),
                strictBounds: false
            };
            map.controls[google.maps.ControlPosition.TOP_CENTER].push(card);
            const autocomplete = new google.maps.places.Autocomplete(
                input,
                options
            );
            autocomplete.bindTo("bounds", map);
            const infowindow = new google.maps.InfoWindow();
            const infowindowContent = document.getElementById(
                "infowindow-content"
            );
            infowindow.setContent(infowindowContent);
            var marker = new google.maps.Marker({
                map
            });
            google.maps.event.addListener(map, "click", e => {
                console.log(e);
                var latLng = e.latLng;
                this.setState({
                    lat: e.latLng.lat(),
                    lng: e.latLng.lng()
                });
                console.log(latLng.lat(), latLng.lng());
                if (marker && marker.setMap) {
                    marker.setMap(null);
                }
                marker = new google.maps.Marker({
                    position: latLng,
                    map: map
                });
            });
            autocomplete.addListener("place_changed", () => {
                infowindow.close();
                const place = autocomplete.getPlace();
                console.log(place);

                if (!place.geometry || !place.geometry.location) {
                    window.alert(
                        "Không tìm thấy vị trí " +
                            place.name +
                            " .Vui lòng chọn trên bản đồ."
                    );
                    return;
                }
                this.setState({
                    lat: place.geometry.location.lat(),
                    lng: place.geometry.location.lng()
                });
                if (marker && marker.setMap) {
                    marker.setMap(null);
                }
                marker = new google.maps.Marker({
                    position: place.geometry.location,
                    map: map
                });
                map.setZoom(16);
                infowindowContent.children["place-name"].textContent =
                    place.name;
                infowindowContent.children["place-address"].textContent =
                    place.formatted_address;
                infowindow.open(map, marker);
            });
        }
    }

Upvotes: 2

rlucatoor
rlucatoor

Reputation: 141

Had the same issue while following the Google Tutorial. In my case the problem turned out to be the async keyword, which was causing the Google Maps script to execute asynchronously while the rest of the page continued parsing. Here's the fix:

  1. Put the Google Maps script after the relevant HTML element (as pointed out by Prashant)
  2. Call the Google Maps script using the defer keyword and not the async keyword. Code:
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places$callback=YourFunctionHere" defer></script>

Using defer makes sure the script is executed when the page has finished parsing (source).

Upvotes: 1

jb4
jb4

Reputation: 666

Your field is TEXTAREA, and from last updates, google maps autocomplete now supports only window.HTMLInputElement (INPUT tag).

Upvotes: 65

Anand Undavia
Anand Undavia

Reputation: 3543

For Angular

I was initializing the autocomplete in ngOnInit() because of which I was getting the error. I simply moved the initialization to ngAfterViewInit() and everything worked fine.

Code:

  ngAfterViewInit(): void {
    this.autocomplete = new google.maps.places.Autocomplete(
      (this._document.getElementById('input')),
      { types: ['geocode'] }
    );
  }

Upvotes: 1

KCarnaille
KCarnaille

Reputation: 1057

I was facing the same issue some days ago, but I've found a solution, if someone is interested :) It's not perfect, it's very tricky, but it does 95% of the job ! I know it's a very old topic, but if it can save somebody...

The idea is to add a custom textarea, and bind the original input text value to the textarea (with keyup, keypress, keydown, change events).

$('.MyInput').on('keyup keydown keypress change', function() {
  $('myTextarea').val($(this).val());
  emptyPlaceholder($(this), 'Myplaceholder text');
});

function emptyPlaceholder(input, placeholder) {
     // The placeholder of the textarea will hide if the input has a value
     if (input.val().length) {
         $('#triggerInput').attr('placeholder', '');
     } else {
         $('#triggerInput').attr('placeholder', placeholder);
     }
 }

Add some css to " hide " the original input. It will hide what you're writing in the input, then you'll only see what is written in your textarea (Important: the z-index of the input has to be superior than textarea one !)

.MyInput {
   color: transparent;
   background-color: transparent; 
}

It's far from being perfect, and I'm open if someone has a better solution !

Upvotes: 1

swapnil kambe
swapnil kambe

Reputation: 123

.pac-container { z-index: 1051 !important; }

Upvotes: -1

Vingtoft
Vingtoft

Reputation: 14656

I had the same problem in Angular2. My solution is to move the initialisation of Google Maps to a function that fires when a user focus in the autocomplete input field. Not the most beautiful solution, but it works.

Code:

private autocomplete_init: boolean: false;

autocompleteFocus() {
 this.autocomplete_init = true;
 if (!this.autocomplete_init) {
  this._autocomplete = new google.maps.places.Autocomplete(document.getElementById("search_address"), {
  componentRestrictions: {'country': 'dk'}
  }
}

HTML:

<input placeholder="Search" type="text" id="search_address" (focus)="autocompleteFocus()" autofocus>

Upvotes: 5

Prashant Kumar Mishra
Prashant Kumar Mishra

Reputation: 230

This is an issue of DOM. Your javascript loads before loading your html document.

Make sure your html elements load first and then only load javascript.

Like

and then

Your javascript code

Upvotes: 18

Imaginary
Imaginary

Reputation: 773

This has been my problem while following the tutorial on Google. The problem is that you should execute the javascript after the page loads, you can call the function on the GET parameter while calling the Google Map script:

<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places$callback=YourFunctionHere"></script>

YourFunctionHere is a callback function means it will only execute after the page loads.

Or you can can call functions after the page loads. Example: window.onload = Yourfunction();

Now, inside that function is where you would do your Google Maps API stuff like document.getElementById('source_map') and all methods that belong to the google class.

Upvotes: 9

Related Questions