admin管理员组

文章数量:1420598

I'm learning react and trying to create a Google places autoplete ponent, inside a rails app the using react on rails gem. Here's what I have so far, need some help finishing it off.

I think I'm having an issue getting the Google javascript library to load correctly. See error message from console below (note I have the proper [KEY] running in my app).

Navigated to /
js?key=[KEY]&libraries=places&callback=initAutoplete:102 Uncaught Yc {message: "initAutoplete is not a function", name: "InvalidValueError", stack: "Error↵    at new Yc (…libraries=places&callback=initAutoplete:139:73"}
Yg @ js?key=[KEY]&libraries=places&callback=initAutoplete:102
(anonymous) @ js?key=[KEY]&libraries=places&callback=initAutoplete:139
google.maps.Load @ js?key=[KEY]&libraries=places&callback=initAutoplete:21
(anonymous) @ js?key=[KEY]&libraries=places&callback=initAutoplete:138
(anonymous) @ js?key=[KEY]&libraries=places&callback=initAutoplete:139
createReactElement.js?74ab:40 RENDERED GoogleAutoComplete to dom node with id: GoogleAutoComplete-react-ponent-f9a3e037-df00-4f35-9a7c-103c33b1208e with props, railsContext: Object {text: "google autoplete"} Object {inMailer: false, i18nLocale: "en", i18nDefaultLocale: "en", href: "/", location: "/"…}
clientStartup.js?0ac5:149 Uncaught TypeError: ReactOnRails encountered an error while rendering ponent: GoogleAutoComplete.Original message: Cannot read property 'Autoplete' of undefined
    at GoogleAutoComplete.initAutoplete (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:3586), <anonymous>:44:48)
    at GoogleAutoCompleteponentDidMount (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:3586), <anonymous>:38:12)
    at eval (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2842), <anonymous>:265:25)
    at measureLifeCyclePerf (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2842), <anonymous>:75:12)
    at eval (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2842), <anonymous>:264:11)
    at CallbackQueue.notifyAll (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2296), <anonymous>:76:22)
    at ReactReconcileTransaction.close (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:3004), <anonymous>:80:26)
    at ReactReconcileTransaction.closeAll (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2398), <anonymous>:206:25)
    at ReactReconcileTransaction.perform (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2398), <anonymous>:153:16)
    at batchedMountComponentIntoNode (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:3130), <anonymous>:126:15)

Here is the relevant code:

index.html.erb

<html>
  <body>
  <%= react_ponent("GoogleAutoComplete") %>

  <script type="text/javascript" src=";libraries=places&callback=initAutoplete"
        ></script>
  </body>
</html>

GoogleAutoComplete.jsx

import React, { PropTypes } from 'react';

export default class GoogleAutoComplete extends React.Component {
  static propTypes = {
    }
  constructor(props) {

      super(props);
        this.state = { 
          autoplete: {} 
        }
    }

    ponentDidMount() {
      this.initAutoplete();
    }

    initAutoplete() {
      // eslint-disable-next-line no-undef
      const autoplete = new google.maps.places.Autoplete((this.refs.autoCompletePlaces), {types: ['geocode']});

      autoplete.addListener('place_changed', this.fillInAddress);
      this.setState({ autoplete });
    }

    geolocate() {
      if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function(position) {
          const geolocation = {
            lat: position.coords.latitude,
            lng: position.coords.longitude
          };
        });
      }
    }

    fillInAddress() {
      const ponentForm = {
        street_number: 'short_name',
        route: 'long_name',
        locality: 'long_name',
        administrative_area_level_1: 'short_name',
        country: 'long_name',
        postal_code: 'short_name'
      };
    // Get the place details from the autoplete object.
      const place = autoplete.getPlace();
      for (let ponent in ponentForm) {
        this.refsponent.value = '';
        this.refsponent.disabled = false;
      }

    // Get each ponent of the address from the place details
    // and fill the corresponding field on the form.
    for (let i = 0; i < place.address_ponents.length; i++) {
      const addressType = place.address_ponents[i].types[0];
      if (ponentForm[addressType]) {
        const val = place.address_ponents[i][ponentForm[addressType]];
        this.refs.addressType.value = val;
      }
    }
  }



  render() {
    return (
      <div>
        <div id="locationField">
          <input 
            id="autoplete" 
            placeholder="Enter your address"
            onFocus={this.geolocate}
            onChange={this.handleInputChange}
            ref="autoCompletePlaces"
          />
        </div>
        <table id="address">
          <tbody>
            <tr>
              <td>Street address</td>
              <td>
                <input 
                  id="street_number"
                  disabled="true"/>
              </td>
              <td>
                <input 
                  id="route"
                  disabled="true"/>
              </td>
            </tr>
            <tr>
              <td>City</td>
              <td>
                <input 
                  id="locality"
                  disabled="true"/>
              </td>
            </tr>
            <tr>
              <td>State</td>
              <td>
                <input 
                  id="administrative_area_level_1" 
                  disabled="true"/>
                </td>
              <td>Zip code</td>
              <td>
                <input
                  id="postal_code"
                  disabled="true"/>
              </td>
            </tr>
            <tr>
              <td>Country</td>
              <td>
                <input
                  id="country" 
                  disabled="true"/>
              </td>
            </tr>
          </tbody>
        </table>
      </div>      
    );
  }
}

I'm learning react and trying to create a Google places autoplete ponent, inside a rails app the using react on rails gem. Here's what I have so far, need some help finishing it off.

I think I'm having an issue getting the Google javascript library to load correctly. See error message from console below (note I have the proper [KEY] running in my app).

Navigated to https://react-on-rails-basic-tutorial-mcl282.c9users.io/
js?key=[KEY]&libraries=places&callback=initAutoplete:102 Uncaught Yc {message: "initAutoplete is not a function", name: "InvalidValueError", stack: "Error↵    at new Yc (https://maps.googleapis./m…libraries=places&callback=initAutoplete:139:73"}
Yg @ js?key=[KEY]&libraries=places&callback=initAutoplete:102
(anonymous) @ js?key=[KEY]&libraries=places&callback=initAutoplete:139
google.maps.Load @ js?key=[KEY]&libraries=places&callback=initAutoplete:21
(anonymous) @ js?key=[KEY]&libraries=places&callback=initAutoplete:138
(anonymous) @ js?key=[KEY]&libraries=places&callback=initAutoplete:139
createReactElement.js?74ab:40 RENDERED GoogleAutoComplete to dom node with id: GoogleAutoComplete-react-ponent-f9a3e037-df00-4f35-9a7c-103c33b1208e with props, railsContext: Object {text: "google autoplete"} Object {inMailer: false, i18nLocale: "en", i18nDefaultLocale: "en", href: "https://react-on-rails-basic-tutorial-mcl282.c9users.io/", location: "/"…}
clientStartup.js?0ac5:149 Uncaught TypeError: ReactOnRails encountered an error while rendering ponent: GoogleAutoComplete.Original message: Cannot read property 'Autoplete' of undefined
    at GoogleAutoComplete.initAutoplete (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:3586), <anonymous>:44:48)
    at GoogleAutoComplete.ponentDidMount (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:3586), <anonymous>:38:12)
    at eval (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2842), <anonymous>:265:25)
    at measureLifeCyclePerf (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2842), <anonymous>:75:12)
    at eval (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2842), <anonymous>:264:11)
    at CallbackQueue.notifyAll (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2296), <anonymous>:76:22)
    at ReactReconcileTransaction.close (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:3004), <anonymous>:80:26)
    at ReactReconcileTransaction.closeAll (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2398), <anonymous>:206:25)
    at ReactReconcileTransaction.perform (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2398), <anonymous>:153:16)
    at batchedMountComponentIntoNode (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:3130), <anonymous>:126:15)

Here is the relevant code:

index.html.erb

<html>
  <body>
  <%= react_ponent("GoogleAutoComplete") %>

  <script type="text/javascript" src="https://maps.googleapis./maps/api/js?key=AIzaSyAnhYQqHo2V5AcFpcKKPX6rz0bVrw7xmZg&libraries=places&callback=initAutoplete"
        ></script>
  </body>
</html>

GoogleAutoComplete.jsx

import React, { PropTypes } from 'react';

export default class GoogleAutoComplete extends React.Component {
  static propTypes = {
    }
  constructor(props) {

      super(props);
        this.state = { 
          autoplete: {} 
        }
    }

    ponentDidMount() {
      this.initAutoplete();
    }

    initAutoplete() {
      // eslint-disable-next-line no-undef
      const autoplete = new google.maps.places.Autoplete((this.refs.autoCompletePlaces), {types: ['geocode']});

      autoplete.addListener('place_changed', this.fillInAddress);
      this.setState({ autoplete });
    }

    geolocate() {
      if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function(position) {
          const geolocation = {
            lat: position.coords.latitude,
            lng: position.coords.longitude
          };
        });
      }
    }

    fillInAddress() {
      const ponentForm = {
        street_number: 'short_name',
        route: 'long_name',
        locality: 'long_name',
        administrative_area_level_1: 'short_name',
        country: 'long_name',
        postal_code: 'short_name'
      };
    // Get the place details from the autoplete object.
      const place = autoplete.getPlace();
      for (let ponent in ponentForm) {
        this.refs.ponent.value = '';
        this.refs.ponent.disabled = false;
      }

    // Get each ponent of the address from the place details
    // and fill the corresponding field on the form.
    for (let i = 0; i < place.address_ponents.length; i++) {
      const addressType = place.address_ponents[i].types[0];
      if (ponentForm[addressType]) {
        const val = place.address_ponents[i][ponentForm[addressType]];
        this.refs.addressType.value = val;
      }
    }
  }



  render() {
    return (
      <div>
        <div id="locationField">
          <input 
            id="autoplete" 
            placeholder="Enter your address"
            onFocus={this.geolocate}
            onChange={this.handleInputChange}
            ref="autoCompletePlaces"
          />
        </div>
        <table id="address">
          <tbody>
            <tr>
              <td>Street address</td>
              <td>
                <input 
                  id="street_number"
                  disabled="true"/>
              </td>
              <td>
                <input 
                  id="route"
                  disabled="true"/>
              </td>
            </tr>
            <tr>
              <td>City</td>
              <td>
                <input 
                  id="locality"
                  disabled="true"/>
              </td>
            </tr>
            <tr>
              <td>State</td>
              <td>
                <input 
                  id="administrative_area_level_1" 
                  disabled="true"/>
                </td>
              <td>Zip code</td>
              <td>
                <input
                  id="postal_code"
                  disabled="true"/>
              </td>
            </tr>
            <tr>
              <td>Country</td>
              <td>
                <input
                  id="country" 
                  disabled="true"/>
              </td>
            </tr>
          </tbody>
        </table>
      </div>      
    );
  }
}
Share Improve this question edited Feb 20, 2017 at 17:36 Michael Lee asked Feb 20, 2017 at 16:50 Michael LeeMichael Lee 4581 gold badge8 silver badges19 bronze badges 1
  • Hi Michael, I know this is an old post but there is an API key in the html script in your question - might be worth editing and removing it :). If you ever want to use this as a react hook, I have a post that would help with creating/using the hook with the google places autoplete service here: atomizedobjects./blog/react/… – Atomicts Commented Nov 21, 2020 at 14:09
Add a ment  | 

1 Answer 1

Reset to default 2

The error occurs because the initComplete() is not available in the global scope. The initComplete() is a React ponent method and you cannot call it outside the ponent.

To pass the callback parameter to Google Maps API, you need to load the library asynchronously, without using the <script> tag like you did.

Please have a look at the following repository to see how they handle the asynchronous loading of Google Maps library.

https://github./fullstackreact/google-maps-react

本文标签: javascriptGoogle Places Autocomplete React ComponentStack Overflow