odoe

ArcGIS API for JavaScript with Polymer

Blog Post created by odoe on Sep 16, 2015

esrijs-polymer.png

 

I did a blog post recently on using Polymer with the ArcGIS API for JavaScript 4.0 beta.

 

You can read more about Web Components here and here.

 

Web components are awesome, because you could do something like this in your HTML.

 

<body>
  <my-awesome-component></my-awesome-component>
</body>

 

And you could have <my-awesome-component> be some awesome user-interface element!

 

Sounds great right? Yeah, web-components aren't quite supported in all browsers yet. But no fear, while browser vendors duke out the spec and details, we can just use awesome libraries like Polymer. Most libraries like Angular, Ember, React and even Dojo Djits provide components of some sort.

 

So what's so great about Polymer? Let's look at a simple component that we want to use to display the current extent of the map.

 

<dom-module id="extent-info">
  <template>
    <div class="extent-details well">
      xmin: <span>{{xminc}}</span><br>
      ymin: <span>{{yminc}}</span><br>
      xmax: <span>{{xmaxc}}</span><br>
      ymax: <span>{{ymaxc}}</span><br>
    </div>
  </template>
  <style>
    .extent-details {
      margin: 1em;
    }
  </style>
  <script>
    var ExtentInfo = Polymer({
      is: 'extent-info',
      properties: {
        xmin: Number,
        ymin: Number,
        xmax: Number,
        ymax: Number,
        xminc: {
          type: Number,
          computed: 'toFixed(2, xmin)'
        },
        yminc: {
          type: Number,
          computed: 'toFixed(2, ymin)'
        },
        xmaxc: {
          type: Number,
          computed: 'toFixed(2, xmax)'
        },
        ymaxc: {
          type: Number,
          computed: 'toFixed(2, ymax)'
        }
      },
      toFixed: function(n, x) {
        return x.toFixed(n);
      }
    });
  </script>
</dom-module>

 

So let's check this out.

 

The root of your component is a dom-module with an id that corresponds to the id given to the Polymer constructor. Then we have a template section. The template section contains the actual DOM elements of your component. This is where you can bind attributes to your Polymer component by using mustache syntax {{bindingVariable}}. These bound variables are defined in the Polymer constructor as properties. In these properties, you can define computed properties. Meaning these are properties that are computed based on other properties, in this case simplifying the precision of the extent numbers.

 

The beauty of these components is that to update them, you simply update the attributes o the DOM element and the computed properties will handle the rest.

 

class Component {
  constructor(data) {
    // add import link
    var href = require.toUrl('app/views/PolymerView/components/ExtentInfo.html');
    var node = document.querySelector('.esriTop.esriRight');
    var link = document.createElement('link');
    link.setAttribute('href', href);
    link.setAttribute('rel', 'import');
    document.body.appendChild(link);

    var el = document.createElement('extent-info');
    node.appendChild(el);
    el.setAttribute('xmin', data.xmin)
    el.setAttribute('ymin', data.ymin)
    el.setAttribute('xmax', data.xmax)
    el.setAttribute('ymax', data.ymax)
    this.element = el;
  }

  update(data) {
    var el = this.element;
    el.setAttribute('xmin', data.xmin)
    el.setAttribute('ymin', data.ymin)
    el.setAttribute('xmax', data.xmax)
    el.setAttribute('ymax', data.ymax)
  }
};
export default Component;

 

Now the easy way to use this with the ArcGIS API for JavaScript 4.0 beta is using Accessors. You can create a Model the extends Accessor and defines the Extent.

 

import Accessor from 'esri/core/Accessor';
import Extent from 'esri/geometry/Extent';
class Model extends Accessor {
  classMetadata: {
    properties: {
      extent: {
        type: Extent
      }
    }
  }
};
export default Model;

 

Since it's an Accessor, you can watch for changes on the Model and update the values of the component with the changes.

 

import Model from './Model';
import Component from './components/ViewProxy';
// Controller links Model and view
class Controller {
  constructor(extent) {
    this.model = new Model({ extent: extent });
    this.view = new Component({
      position: 'topright',
      xmin: this.model.extent.xmin,
      ymin: this.model.extent.ymin,
      xmax: this.model.extent.xmax,
      ymax: this.model.extent.ymax
    });
    this.model.watch('extent', (val) => {
      this.view.update({
        xmin: val.xmin,
        ymin: val.ymin,
        xmax: val.xmax,
        ymax: val.ymax
      });
    });
  }
};
export default Controller;

 

That's it. You can start building out a bunch of reusable components that can be composed together to create an entire application if you want.

 

There's currently a project called esri-polymer on github from James Milner of Esri UK that's really cool. It's based on the current ArcGIS API for JavaScript 3.x, so no Accessors, but it has enough components that it allows to put an application together without writing any JavaScript.

 

This is the future of what's to come in web development, but screw the future, you can do this stuff now.

 

For more geodev tips and tricks, check out my blog.

Outcomes