google-maps-react icon indicating copy to clipboard operation
google-maps-react copied to clipboard

InfoWindow javascript events not triggering for within window

Open CapnMorgan71 opened this issue 8 years ago • 8 comments

None of the buttons ... A ,B ,C ,D do not fire... i ahve been trying links, buttons and header elements all do not fire events

                <InfoWindow
                        marker={this.state.activeMarker}
                        visible={this.state.showingInfoWindow}>
                            <div>
                                <button onClick={() => {this.setState({ showingInfoWindow:false });}}>A</button>
                                <button onClick={(e) => {this.setState({ showingInfoWindow:false });}}>B</button>
                                <button onClick={(e) => {e.preventDefault();console.log(e);}}>C</button>
                                <button onClick={this.onClickMarkerAgentName}>D</button>                                    
                            </div>
                </InfoWindow>

CapnMorgan71 avatar Feb 03 '17 21:02 CapnMorgan71

@ CapnMorgan71 : do you find any solution on it ? i am also getting same problem.

mayurmate149 avatar Feb 10 '17 09:02 mayurmate149

Running into the same issue. The problem is the way the actual HTML that is passed to the Google InfoWindow is rendered.

The library uses renderToString from react-dom/server, which is obviously used in server-side rendering. It just renders a component to HTML, but what it does not do, is actually registering any client-side React stuff to it, so event handlers won't work.

I think it needs some kind of way of passing it through ReactDOM.render() or something.

dmeenhuis avatar Mar 10 '17 08:03 dmeenhuis

To make this work, You can pass a div with an Id to InfoWindow. Then in onMarkerClick you can render any elements that need to respond to mouse events using ReactDOM.render(). Thanks, @dmeenhuis sending me down that path.

coreyar avatar Mar 29 '17 15:03 coreyar

Hi, I ran into the same issue, and fixed it with Corey's method. Here some code for the beginners like me. All of that is in InfoWindow.js obviously.

Start by adding a div to the InfoWindow const iw = this.infowindow = new google.maps.InfoWindow({ content: '<div id="iwc"/>' });

Now when updating the content (so in method updateContent), use ReactDOM.render(React.Children.only(children), document.getElementById("iwc")); This assumes your InfoWindow has a single child, so use a container or modify this.

At this point, this won't work as updateContent is called before the InfoWindow is actually open. So change the test in componentDidUpdate to

if (this.props.visible && prevProps.visible && this.props.children !== prevProps.children) {
    this.updateContent();
}

Now you just need to update the content when opening the window, so add this.updateContent() in openWindow.

Hope that helps!

etienne-lambert avatar Oct 21 '17 22:10 etienne-lambert

Hi All, Thanks for all your comments. I manage to build (after reading your suggestions) an example that works without modifying the Infowindow code.

The infoWindow itself should only contain a placeholder div with a unique id:

  <InfoWindow
    marker={this.state.activeMarker}
    visible={this.state.showingInfoWindow}
    onOpen={e => {
      this.onInfoWindowOpen(this.props, e);
    }}
  >
    <div id="iwc" />
  </InfoWindow>

And inside the Mapcontainer, you define an onInfoWindowOpen callback, that inserts a single component/container with the onClick event and render it to a placeholder div:

onInfoWindowOpen(props, e) {
    const button = (<button onClick={e => {console.log("hmapbuttoni1");}}>mapbutton</button>);
    ReactDOM.render(React.Children.only(button), document.getElementById("iwc"));
  }

Here is a working example.

rbahumi avatar Aug 28 '18 20:08 rbahumi

Another approach is to use portals:

class ElementInfoWindow extends InfoWindow {
  renderInfoWindow() {
    InfoWindow.prototype.renderInfoWindow.call(this);
    this.elem = document.createElement('div');
  }
  renderChildren() {
    return this.elem;
  }
  render()  {
    const {children} = this.props;
    return this.elem ? ReactDOM.createPortal(children, this.elem) : null;
  }
}

ktosiek avatar Apr 04 '19 13:04 ktosiek

Hi All, Thanks for all your comments. I manage to build (after reading your suggestions) an example that works without modifying the Infowindow code.

The infoWindow itself should only contain a placeholder div with a unique id:

  <InfoWindow
    marker={this.state.activeMarker}
    visible={this.state.showingInfoWindow}
    onOpen={e => {
      this.onInfoWindowOpen(this.props, e);
    }}
  >
    <div id="iwc" />
  </InfoWindow>

And inside the Mapcontainer, you define an onInfoWindowOpen callback, that inserts a single component/container with the onClick event and render it to a placeholder div:

onInfoWindowOpen(props, e) {
    const button = (<button onClick={e => {console.log("hmapbuttoni1");}}>mapbutton</button>);
    ReactDOM.render(React.Children.only(button), document.getElementById("iwc"));
  }

Here is a working example.

Thank you so much for this!!!

dougschallmoser avatar Nov 19 '20 00:11 dougschallmoser

Another approach is to use portals:

class ElementInfoWindow extends InfoWindow {
  renderInfoWindow() {
    InfoWindow.prototype.renderInfoWindow.call(this);
    this.elem = document.createElement('div');
  }
  renderChildren() {
    return this.elem;
  }
  render()  {
    const {children} = this.props;
    return this.elem ? ReactDOM.createPortal(children, this.elem) : null;
  }
}

Thank you so much this work in react 18

afnan-1 avatar Jul 03 '22 23:07 afnan-1