ArcGIS JS API 4.0 beta1 Accessors

ArcGIS JS API 4.0 beta1 Accessors

Rene Rubalcava | July 16, 2015

Ok, so technically the ArcGIS API for JavaScript 4.0beta1 isn't a final product, but it has some really nice features that users and developers should really enjoy and be excited about. Yeah yeah, 3D, cool and all and I'm sure you'll hear plenty about it. But I want to talk more bare metal. I want to talk about ES5 Accessors in the API. This is the good stuff folks.

What the what?

You can go ahead and read some details about Accessors out there and the 4.0beta1 doc here and the guide here.

But let's show what you can basically do!

view.watch('extent', function(newValue) {/**/});

Is that an event or what? No, these are not events these are observable Objects, this is kind of like some syntactical sugar or Object.observe().

Object.observe(view, function(changes) {
  var newValue = changes.filter(function(x) {
    return x.name === 'extent';
  }).shift();
});

I don't know about you, but the former method is a lot cleaner to me. Does that mean there are no more events in the API? Not at all, there's events, there's more Promises, which I have written about before. What this does mean, is you can use Accessors to watch for property changes and act upon them. This is much more fine-grained than simply listening for some events to happen.

Let's say you want to run a count on the number of features in your extent as the map is panned around. Normally you may listen for the extent to change and then run a query against a service, which is cool and all, but the extent changes every time you slightly pan the map, so that's an awful lot of queries to try and do. Better yet, you can watch for when view.stationary is updated to either true or false. So you can do something like this:

query.watch('geometry', function() {
  queryTask.executeForCount(query).then(function(results) {
    // do something with results
  });
});
view.watch('stationary', function(val) {
  if (val) {
    query.geometry = view.extent;
  } else {
    // message about map panning
  }
});

Woah woah! The Query is an Accessor too? That's right, Accessors are all over the place. But wait a second, I don't like having to do that boolean check when the stationary property changes. There's a util for that, esri/core/watchUtils. This has some nifty little helpers for watching property changes, but the ones I'm interested in are boolean helpers.

watchUtils.whenTrue(view, 'stationary', function() {
  query.geometry = view.extent;
});
watchUtils.whenFalse(view, 'stationary', function() {
  // message about map panning
});

Now that is pretty cool. You can see the full sample below. Accessors on jsbin.com

That looks like Stateful

I know, right? At first glance it might look like you are dealing with dojo/Stateful. But the main differences are in the API. With Stateful when you are watching for changes, the callback signature on a changed property looks like this:

function(name, oldValue, value){}

The new value returned is the third argument in. You know how I write this in my apps?

function(a, b, value){}

Because the new value is all I care about.

There's also setters. In Stateful you do this:

myObj.set('prop', newValue);

With Accessors, you can just do this:

myObj.prop = newValue;

Bam, magic!

I would actually say that Accessors are closer to dmodel than Stateful. Because you can have computed properties with Accessors. The Accessor module is a mixin that can be used with dojo/_base/declare. So you could do something like this:

var Model = declare([Accessor], {
  classMetadata: {
    properties: {
      fullName: {
          dependsOn: ['firstName', 'lastName'],
          readOnly: true
      }
    }
  },
  _fullNameGetter: function() {
    return this.fullName + ' ' + this.lastName;
  }
});

What we have here is a model that uses the Accessor mixin and sets up a couple of properties. Then we have a readOnly computed property that depends on other properties. Now imagine you did this with your application using attribute data from a FeatureService and you could define some computed properties to easily display. That is pretty damn cool.

More benefits

So we've seen how Accessors are pretty useful to monitor the state of your application. Well, when I think of stateful applications, I think of React. How useful would Accessors be for someone that wants to incorporate the ArcGIS API for JavaScript into a React application. Well, why don't we take a look!

Here is a very simple React component that will display the time of day of the environment in the Scene of your application.

var TimeClock = React.createClass({
  getInitialState: function() {
    // Define an initial state
    return {
      published: true
author: Rene Rubalcava
date: new Date("Sun Mar 15 2015 09:00:00 GMT+0100 (CET)")
    };
  },
  componentDidMount: function() {
    // Watch for updates to the date property
    this.props.view.watch('environment.lighting.date', function(val) {
      this.setState({ published: true
author: Rene Rubalcava
date: val });
    }.bind(this));
  },
  render: function() {
    // Return component
    return (
      <div>
        <label>Time: {this.state.date.toTimeString()}</label>
      </div>
    );
  }
});

Let's look at this in action! Using React - 4.0 beta 1 on jsbin.com

Look at that! A simple React component working flawlessly with Accessors! You have to admit, that is pretty cool.

Let it sink in

There is a lot more to the 4.0beta1 release that I haven't covered, but will in the coming weeks. I just happen to think that Accessors are a really great addition to the API and will help developers solve a lot of pain points they may have run into when dealing with events. Check out the What's new section in the docs.

Learn about your MapView and SceneView. Embrace your views people, the map is simply a container, all the action happens in the views now! So go on, bang on the 4.0beta1 API, kick the tires, Check out Accessors and see what you can come up with.