Bindy

do this

            
              // map is ready to roll
              map.on('idle tilesloaded bounds_changed', function interactive(e) {
                // remove the remaining events
                map.off(interactive)
                // do the stuff
              })
            
          

instead of this

            
              var fired,
                // map is ready to roll
                interactive = function interactive() {
                  // don't run this more than once
                  if (!fired) {
                    fired = true
                    // remove the remaining events
                    interactiveListeners.forEach(google.maps.event.removeListener)
                    // do the stuff
                  }
                }
              var addListener = google.maps.event.addListener,
                interactiveListeners = [
                  addListener(map, 'idle', interactive),
                  addListener(map, 'tilesloaded', interactive),
                  addListener(map, 'bounds_changed', interactive)
                ]
            
          

Get started

Include the scripts

      
        <script src="https://maps.googleapis.com/maps/api/js?v=3"></script>
        <script src="bindy.js"></script>
      
    

Add some events

      
        var poi = new google.maps.Marker({
          position: {
            lat: 45.517,
            lng: -122.670
          }
        })

        poi.on({
          click: function() {
            console.log('clickity click!')
          },
          'mouseover mouseout': function(e) {
            console.log("you " + e.event + "'d me!")
          }
        })
      
    

Why

Let me start by saying that the Google Maps JavaScript API is excellent. It is well documented, easy to work with, and for the most part consistent. This is not intended to be a fix, I do not believe they've done it wrong. Rather, it is an attempt to formalize my project-to-project efforts of creating a familiar event API for Google Maps.

Actual why

Each time I work with the Maps API I create an event wrapper for the google.maps.event namespace. From scratch. For some reason I am compelled to do this before getting any actual work done. Whether or not that's a good thing is a topic for another day. Anyway, it all started out very simple. Bind multiple events at once, one time bindings, return a function to remove said events, etc. Over time it started to look a bit like jQuery's unintelligent cousin so I figured hey, why not match the jQuery event API sans selectors and data? It's familiar to many and brilliantly concise. This is my best crack at doing just that.

What you get

The following API for any object or class that extends google.maps.MVCObject. There are many, many classes in the Maps API that extend MVCObject. 33 or more according to my ctrl+f of "extends MVCObject".

for example

will come packed with .on(), .one(), and .off()

the EventObject

Not all events are created equal. That is, not all of them have an EventObject. For the sake of consistency we will always pass an EventObject as the first argument to a handler function.

      
        // custom
        EventObject {
          event     : event name,
          timeStamp : event creation time in milliseconds
          ...         props from native event, if any
        }

        // native
        google.maps.MouseEvent {
          latLng : the latlng where the event occurred,
          stop() : prevents event from propagating further
        }
      
    

API

.on(events [, handler])

Attaches the given handler function to one or more events

object.on(events, handler) object.on(events)
example
        
          /**
           * NOTE
           * this object is used in all the demos so just know that
           * when you see portland.*() elsewhere, it's a real thing
           */

          var portland = new google.maps.Marker({
            position: {
              lat: 45.5177241,
              lng: -122.6704882
            }
          })
        
      
        
          portland.on('mouseover mouseout', function(e) {
            if ('mouseover' == e.event) {
              console.log("welcome to a whole lot of Awesome")
            } else {
              console.log('aww, sad to see you go')
            }
          })
        
      
or
        
          portland.on({
            'mouseover mouseout': function(e) {
              if ('mouseover' == e.event) {
                console.log("welcome to a whole lot of Awesome")
              } else {
                console.log('aww, sad to see you go')
              }
            }
          })
        
      

.one(events [, handler])

Attaches the given handler function to one or more events. At most, the handler will be called once per event

object.one(events, handler) object.one(events)
example
        
          /**
           * THE HAPS
           * user    -> clickity click (2x)
           * console -> you clicked on Portland! (1x)
           */
        
      
        
          portland.one('click', function(e) {
            console.log('you clicked on Portland!')
          })
        
      
or
        
          portland.one({
            click: function(e) {
              console.log('you clicked on Portland!')
            }
          })
        
      

.off([events] [, handler])

Removes a previously bound handler function

object.off(events [, handler]) object.off(events) object.off(event) object.off()
example
        
          var handler
          portland.on('click mouseover', handler = function(e) {
            // do the things
          })

          // remove all events bound to `handler`
          portland.off(handler)

          // remove all click events
          portland.off('click')

          // remove all click events bound to `handler`
          portland.off('click', handler)

          // remove all mouseover events
          portland.off('mouseover')

          // remove all mouseover events bound to `handler`
          portland.off('mouseover', handler)

          // remove all click and mouseover events
          portland.off('click mouseover')

          // remove all click and mouseover events that are bound to `handler`
          portland.off('click mouseover', handler)
        
      
        
          portland.one('click', function() {
            // do stuff once
          })
        
      
is equivalent to
        
          portland.on('click', function(e) {
            this.off(e)
            // do stuff once
          })
        
      
        
          portland.on('click position_changed', function handler(e) {
            // do stuff once

            /**
             * remove the remaining events bound to `handler`
             * making sure we only run this code one time
             */
            this.off(handler)

            /**
             * `e.event` can be 'click' or 'position_changed'
             * depending on which event happened first
             */
            console.log(e.event)
          })
        
      

object.off() explained

        
          // remove all the things
          portland.off()
        
      

Okay, I'll admit that this method doesn't look crazy special.. but it does offer a single important advantage over the provided clearInstanceListeners method.

        
          // remove all the things
          portland.off()

          // remove ALL the things, actually
          google.maps.event.clearInstanceListeners(portland)
        
      

While object.off() will remove all the events that have been bound via object.on and object.one, it will not remove events bound at the objects instantiation.

When and why is this useful? Awesome question. As it stands, the Maps API doesn't actually support full tear-down of an google.maps.Map instance. If you're into recycling you may use a single, or as few as necessary, map instances throughout the lifetime of your single page app. While you may want to remove a map's event listeners while it's not in use, you likely don't want to remove the ones it came with. So how do you remove not too many, and not too few, but just the right amount?

        
          map.off()
        
      

And if you really do want to remove all the events?

        
          map.off(true)
        
      

tada