View Models in ArcGIS JS API
Rene Rubalcava | December 20, 2015
These releases have introduced Vector Tile Support, new Popup and now with 4.0beta3 release, View Models.
What is a View Model
Since 4.0beta1, we were introduced to this concept of the map and view, which basically treats the map as a data source for a view. That view could be a regular 2D MapView or a 3D SceneView.
Well, this concept is now being introduced into the out-of-the-box widgets in the API. So you can use the widgets provided as you normally do or you could take the View Model of a widget and create your own interface for it. The View Models handle all the heavy lifting for you, you just need to build the user experience around them as you like.
The out-of-the-box widgets in the API are built on top of Dijits. Dijits are a tried and well-tested UI framework for Dojo. Some may say Dijit is getting a little long in the tooth, but remember, Djits have been around as long as jQuery, longer than most modern frameworks and are used heavily in enterprise development. Dijits provide solid i18n support and have been battle tested against just about every browser oddity imaginable. Web Component like syntax, templates, data-binding and more, remember... Dojo already did that. Even if Dijits seem a little dated at this point, they are getting a facelift with the new flat theme.
Dijits aren't perfect, but they are solid. However, lots of developers may want to integrate the ArcGIS JS API into their applications and use their framework of choice to handle the bulk of their user-interface.
If you are familiar with my blog at all, I love frameworks. View Models make this much easier to do.
I'm going to cover a few different examples of how you might use these new View Models in your framework of choice. I'll be covering the following:
Roll up your sleeves boys and girls, it's time to party.
To find out how the View Models in the 4.0beta3 API work, you can check out the docs.
For example, if you want to find out about the ZoomViewModel, look at the docs for the Zoom Widget, you will see a property for a viewModel that leads to the ZoomViewModel. All the doc'd widgets in the 4.0beta3 API follow this same pattern, so you can see what the docs for ViewModels look like.
Every View Model constructor takes a View. There might be a couple that take an extra property, but at minimum, they need the View. From there, they will interact with the View as needed and provide methods and properties you can hook into create your own interface.
I'm a big fan of React, like I really dig React. React isn't so much a framework as it is a UI library, but that makes it a perfect candidate for using with View Models. I've already demonstrated in the past how easy it is to use React with the ArcGIS JS API, and now it just got easier.
In this sample, everything is a React component using View Models, even the Zoom buttons.
As you can see, the plus/minus buttons for the zoom control will enable/disable based on the max/min zoom level of your View. This is a regular React component that has the ZoomViewModel as it's state and some other state dependencies based on the state of the ZoomViewModel. We just watch for some property changes.
This doesn't look too different from the default widget, so let's try something more interesting, like BasemapToggle widget.
This is a slightly more complicated UI that will display the basemaps as two little picture cards that switch spots as you toggle the map.
With the entire UI built as React components, I can even do cool stuff like add a transparency to the whole UI as you interact with the map view.
You can see a live demo here.
I like Ember, a lot. It can take some getting used to and could be a bit constraining at times, especially when using the ember-cli, but at least it's uniform. I don't agree with everything Ember does, but it's still a very solid framework that makes app development very consistent.
Ember makes it incredibly easy to use View Models, because it's very easy to pass properties between components.
The UI for these is very simple and you can pass the view between them very easily.
Let's look at the Home Button component.
Very simple, when the view is added, it creates a new View Model. When it's clicked, it uses a method on the View Model to return to the default extent of the View. No fuss.
This sample also demonstrates how the map is treated as a data source for the view and how you might use that in an Ember application.
We treat the map as an Ember service and this allows us to take advantage of dependency injection to add it to our Map View component.
Ember actually turns out to be a great example of using View Models from the ArcGIS JS API.
One of the most popular posts on this blog is Using Angular with ArcGIS JS API. I have an odd relationship with Angular 1. I can appreciate it, but at times I curse it for being over-engineered. I may get crap for it, but that's how I feel. It's a solid framework and there's no denying it's a popular one.
I haven't really had an opportunity to work with Angular 2 much, but I have been wanting to give it a solid try.
One of the things I've been ashamed of is that I couldn't figure out how to use the Dojo AMD loader in the JS API with SystemJS, which is what Angular 2 uses. I recently came across a sample where someone was using System.register() to pre-load AMD modules into SystemJS to get this working. This is very similar to what the ember-ci-amd addon does to work with the funky loader Ember uses.
So after many beers and tears, I came up with this solution.
You basically require your dependencies first, then iterate over them and create a dummy modules in SystemJS and add each dependency to it. This method could probably use some fine-tuning, but it works.
With that done, I could create some components.
Directives are basically just components now and I guess become directives when part of another component. I kind of wish they would have come up with a different naming convention here. But it works ok. Again, View Models work just fine in this situation. I had issues working the subscribing to RxJS 5 Subjects used in Angular 2, so I fell back to dojo/topic to pass service updates around.
Again, I don't know Angular 2 very well yet, so this code could probably be a little better.
Here is a live demo of using View Models with Angular 2.
In this file, I initialize the View Model and pass all updates to the Elm application.
The Elm app will take the updates from the View Model and maintain the state of the UI. So for the SearchViewModel it will take the suggested search results and add them as a list to the UI. This is also an example where the UI component doesn't need everything from the View Model, so you only need to handle what you need and not implement everything in the View Model.
Here is a live demo using the SearchViewModel with Elm. It's still needs some work, as I think I'm updating the state too often, but it's a good start.
Code what you want
I could keep going, adding even more frameworks. I could Angular 1, Knockout, Backbone, Mithril and on and on, but I think you get my point.
View Models give you the freedom to build your UI as you wish.
Here is a summarized list of frameworks with View Models samples.
If you're using ViewModels, you're going hardcore. If you don't need to dig that deep, stick with the out-of-the-box widget implementations. They're well tested and simply work.
But... if you have that itch and you area already building your application around another framework, you should be able to easily integrate View Models with them.
The View Models are still being tested and some of the APIs may change, so keep an eye out for when the 4.0 final lands in the future to see what changes might come about.
Until then, give the View Models a try and see what you can come up with. Most of all, have fun!