polymer Google Map Mark With Built in Cache C - Adding Search Ability to our custom element


Example

For Searching a place, we use the powerful element that Polymer ships, called google-map-search .

All you need to do, is pass

  • a map object and
  • a query string to the element like so:
<google-map-search map=[[map]] query=[[query]]></google-map-search>

How do we pass the map object? Where do we get that from?

Simple!

When you invoke the google-map element, bind your custom element ’s property map, to the element’s property map.

So, we invoke the google-map element like so:

<google-map api-key="whatever key you generated for google's javascript API" map={{map}}></google-map>

Note:

We do a two way data bind for map above, when invoking the google-map polymer.

It is represented by the curly braces {{}} instead of a one way binding indicated by square braces[[]].

When we do a two way bind,

  • Whenever our custom element g-map’s map property changes, google-map element is notified

and,

  • Whenever google-map’s map property changes, we are notified in our custom element g-map.

So, with the two way data binding in place, anytime the map object changes in google-map, our custom element is updated with the changes.

and we pass the map object as an attribute to the element google-map-search, so that , any search results are marked in the current map rendered.

How does our custom element’s DOM look at this moment?

<template id="google-map-custom-element">
 
<google-map-search map=[[map]] query=[[query]]></google-map-search>
<google-map api-key=[[apiKey]] map={{map}}></google-map>
</template>

We never added the map and query properties for our custom element!

Add the properties in the registration call to Polymer

Polymer({
 
    is:"g-map",
 
    properties:{
 
        map:{
 
            type: Object
 
        },
 
        query:{
 
            type:String,
 
            value:""
 
        }
    }
 
});

Now that we have registered the properties, we note, that we

  • Are getting the currently rendered map as an object – via data binding and storing it as a local property also called map,
  • Have a property query, passed to google-map-search

Accepting User Input as Search Query

But who gives us the query to search for? Err! right now? NOBODY.

Thats precisely what we do next.

Let us add a search form, which the user who renders the map, would use to input a query. We need inputs for the search box, and we use Polymer’s iron input.

Adding a Search Form

Include the necessary iron elements at the beginning of the file g-map.html

<link rel=import href=../bower_components/iron-input/iron-input.html>
<link rel=import href=../bower_components/iron-icon/iron-icon.html>
<link rel=import href=../bower_components/iron-icons/iron-icons.html>
<link rel=import href=../bower_components/iron-icons/maps-icons.html>

We want the search form, at the top left corner, so we add an iron input with position absolute, and some css to pin it there.

So, wrap the DOM for our custom element, inside a div called “map-container“, and add a child div called “search_form“.

<template id="google-map-custom-element">
    <div class="map-container">
         <google-map-search map="[[map]]" query="[[query]]"></google-map-search>
         <google-map api-key="[[apiKey]]"></google-map>
         <div class="search_form">
             <iron-icon icon="icons:search" on-tap=__search></iron-icon>
             <input is="iron-input" placeholder="Search Places" type=text name="search" bind-value="{{query}}">
         </div>
     </div>
 </template>

Add some basic css to pin the search form we wrote to the top right of the map

.search_form{
    position: absolute;
    top:10px;
    right:10px;
}
.search_form iron-icon{
    position: absolute;
    right: 1px;
    top:1px;
    cursor: pointer;
}

And , then when we refresh, we have this. The search form at the top right

enter image description here

All that is left to do is, for us to provide an input to google-map-search element, via the query property of our custom element.

So, we bind our property “query”, to the iron input in the search form. like so:

<input is="iron-input" placeholder="Search" type=text name="search" bind-value="{{query}}">

Note:

We bind our custom element’s property query, to the search input using,

“bind-value” attribute of an iron input.

So, bind-value={{query}} in the above iron input, makes sure, any changes to the text inside the iron input, is notified back to the query property.

With our current setup,

For every alphabet a user types into the search box, a search happens, which slows down the map, and Consumes the limit on our API Key.

Why?

Because, our custom element’s property query, is bound to the iron input, and every letter typed into the iron input, changes the value of “query“, which then affects the html in

<google-map-search map="[[map]]" query="[[query]]">

causing a search to happen

Our solution is simple! Just bind the “query” attribute of google-map-search element, to a separate property.

Let us say, we create a property “searchQuery” for our custom element.

Add this, below the “query” property in the Polymer call

searchQuery :{
 
    type:String
 
}

Next, change the bind in google-map-search element call in our custom element’s DOM

like so:

<google-map-search map="[[map]]" query="[[searchQuery]]">

Lastly, Note that we added an iron icon (search icon) to our search form?

<iron-icon icon="icons:search" on-tap=search></iron-icon>

Let us add that search function to our custom element. It is called on tapping the search icon.

In our search method, we assign whatever is there in the search box, to the “query” attribute of google-map-search!

Add this function, after the “properties” object in the polymer call for registration.

//paste this after, the properties object
 
search: function() {
this.query = this.searchQuery;
}

Very Nice! So, Now, A Search happens only on tap of the search icon.

Display The Search Results

We have

  • Rendered a Map
  • Pinned a search form to the Map
  • Wrote the functionality to search on tap of the search icon

Now we need to display the results.

For that, we need to bind the results from the google-map-search element, onto a local property.

So, Let us create a property for our custom element g-map, and name it results duh!

In the Polymer registration call, add the property results of type object in the properties declaration

results:{
 
type:Object
 
}

And bind the results property of google-map-search to the local results property you defined above.

<google-map-search results={{results}} map=[[map]] query=[[query]]></google-map-search>

With that in place, let us refresh the page, and search for starbucks on the map.

enter image description here

Nothing happened!

Well Duh! we just bound the results from google-map-search, to the results property. Did we write anything to display them on the map? NO!

We Need to.

So, we know, that the Polymer element google-map-search, returns an array of markers as results.

We need to loop through the array, and place markers on the map.

So, we write a dom-repeat template, within our element, to display the markers for each result

like so:

<google-map api-key=[[apiKey]] map=[[map]]>
 
    <template is="dom-repeat" items="{{results}}" as="marker">
        <google-map-marker latitude="{{marker.latitude}}" longitude="{{marker.longitude}}">
            <h2>{{marker.name}}</h2>
            <span>{{marker.formatted_address}}</span>
        </google-map-marker>
    </template>
 
</google-map>

And Now on refresh, we see this

enter image description here

Very Nice!

We have successfully added the search functionality to our custom element.

All we need to do is,

write this in our index.html

<g-map api-key="Whatever API key you generated"></g-map>

And you get a map on which you can search!