Tag Archives: arcgis

Node for your ArcGIS Dev

Need a local server anyway

One of the things that tripped a lot of users up when the ArcGIS JavaScript API moved to version 3.0 and started using Dojo 1.7 as it’s core was the fact that you needed to use a server to test your applications. This is by no fault of the ArcGIS API team, it’s just the way Dojo works as part of the AMD loading. This isn’t the kind of thing Esri can fix, nor is going away, so users will need to deal with it. And let’s be honest, best practices would dictate that you probably should have been developing with a local server of some sort anyway.

There are various solutions to work with this. If you use a flavor of Visual Studio, you are in the clear. You could use something like XAMPP, which is a great choice especially if you will be deploying to an Apache environment (it even comes in a portable version for usb drives). I still use both of these methods on a regular basis. But as usual, I was looking for something better. I wanted an easy way to to develop, build tools, test, debug and the all critical build and deploy.

So I turned to Node.

The Node less traveled

I have dabbled in some node in the past, but it has been a while as I have had other projects to work on. So I was sitting there drifting off to sleep in my vanpool (eco-friendly, of course) on the way home from work when it hit me. Why can’t I just build a template app that I could run in node to serve my app to test and debug? It’s just another web page after all. One of the reasons I like to use MVC to build my apps is it’s easy to write an underlying REST API side by side with my web app. Node devs do this kind of thing with their eyes closed while sipping lattes from a Tardis mug (adding to wishlist) all the time.

So I put a template project together on github.

The Point

Using this method makes it very easy to get started. One of the great things about working with Node and the connect framework that expressjs uses is the ability to drop in middleware, which is basically another word for extensions.

So in this case, I am using Jade for an HTML template engine, although you can use any engine you desire or none at all. There is a less-middleware which not only compile less css for you when it is served, but optimize it as well. I am also using express-uglify, which will minify my js files from the server. This means I don’t need to create a release build using r.js or some other method to deploy my application. That to me is very cool. If you come from a .NET/MVC4 background, this is all very analogous to the Web Optimization tools.

I came across a method on stack overflow to load scripts into a jade template that you can see in router/index.js. This is where you can set the title of your page and tell it what scripts you may want to load to shim up your application.

The bulk of the work is done under the public/ folder. This is all stuff I use in production on a daily basis. This would be where you do most of your actual ArcGIS JS dev. I use a config.json that could probably use a README.MD for options, but for now you can load dynamic and feature layers. If you review the code, you should be able to figure it out. Ideally, this config json would be a web service responseThis config json is served from a url endpoint, but could come from MongoDB. I’m still playing with this in my development.

You may notice lack of tests. I am a horrible person. I had some QUnit tests, but nothing comprehensive. I’ll be adding in some mocha tests as soon as I can, which would make it easy to run my test from the command line and probably even on save in my vim environment.

The Proxy

A lot of ArcGIS JS dev requires the use of a proxy, for long queries and CORS and edits, it just comes in handy quite a bit. Obviously, Esri doesn’t provide a node version. I attempted to make one with http-proxy and I think I was somewhat successful. I got it to proxy to external sites ok, but it has not been extensively tested. This is where my node-fu is weak, so no guarantees here, but I am more than open to assitance (or ridicule) on this subject on how I did it. –Update: I think I may have the proxy working as expected. Doesn’t handle tokens just yet. Keep an eye on git repo for further updates.

Will this work?

So you may be asking if all this works. It is totally experimental on my part. I really like developing in this environment and I hope to use it to deploy a couple of projects in the future. You can host node apps in IIS with iisnode if you are an IIS shop. I’m hoping some people will be open to try a solution like this. You could deploy directly to nodejitsu to streamline the process. I was easily able to deploy it to Nodejitsu, which you can see here.

Are you high?

This was a project I got really excited about because I think it opens up some cool possibilities. Say for example you have some bit of code that doesn’t interact with the DOM, but could be a little complex for the client to handle. Offload it to a node module in your development environment. I’m going to add in the esri/geojson-utils as a node module for geojson/esrijson conversions. I have a lot of ideas on how I can use this approach for some projects that have proven a little tricky.

In the end, I do all this for fun and every once in a while, something useful comes out of it. So take it, play with it and maybe you’ll find some use out of it as well.

2013 Goals: No Idle Hands

2012 not as planned

2012 is wrapping up, so I thought I would gather my 2013 resolutions a little early in case the world doesn’t end this week (12-21-2012 oh no). As usual, I look back on what I had set out for myself last year and as usual not much went as planned. I don’t really discuss my personal life here, but it was a rough year for my family in 2012, so when the year started I didn’t think I would really get much done professionally. I was wrong.

As far as languages to learn/improve that I outlined for last year, not much node or Ruby, and I’ll get to why in a minute. Silverlight, sort of, but did work on a WPF project, so got more familiar with XAML. For keeping my skills well-rounded, I have gone over quite a bit of algorithms material. I did not get in to Lisp, but I did start down the path of Erlang and Erlang web apps for some reason and I am fascinated by it.

What the year has been, is very busy. I have picked up extra work that has involved lots of JavaScript, SQL, .NET, some iOS/Andoid and even custom Windows Workflow activities for Geocortex. It’s been pretty exciting to work on new stuff and the feedback has been amazing.

Stacking my Legos

My goals for 2013 are going to be focused on taking on some professional challenges and not just limited to programming. It will involve improving my current skills and becoming a well-rounded GIS professional.

At the moment, I am not too concerned about learning a new programming language (except R, I want to learn R). I am more focused on improving in the languages I am already familiar with or know and improving on the available frameworks and tools. I’m pretty confident in my JavaScript skills, but I always plan on sharpening them and it will continue to be my primary development language in 2013. For example, this year I went from heavily relying on jQuery/Backbone to minimizing my workflow so I only use Dojo with ArcGIS JS API. It’s clean, it’s simple and keeps me focused.

To keep my skills fresh, I have a subscription to a couple of online training sites. The first is Pluralsight, which has proven invaluable as a learning resource, especially for .NET and the Windows Workflow stuff I did this past year. Not cheap, but highly recommended. I also recently signed up for TekPub. I was drawn in by the Postgresql video, but stayed for the great TekPubTV and other online screencasts.

GIS skills or thrills?

I came across a couple of informative GIS career articles this year. One is the Spatial Career Guide for Undergrads by Justin Holman. Despite the title, I think it can apply to current professionals as well. The other is a quick read titled The GIS Career, Revisioned. I would recommend these to any prospective or current GIS professionals.

Like many things, GIS skills can go soft when you don’t use them everyday. I mainly spend my time in developer mode, so I have made it a point to exercise my spatial analysis/stats muscles and will continue to do so. I am looking to get more familiar with R and other open-source spatial tools. This past year I have gotten to work directly with a database architect and I’ve learned quite a bit, so I plan to improve my db skills this coming year and dive into some PostGIS goodies too. As far as cartography goes, it’s not my biggest strength, but I bought The Cartopher’s Toolkit to help me not suck at it. Do I need to cover all these points as a GIS pro? I suppose one could focus on a single career path, but I’m in way too deep at this point. Besides, that seems like it would be boring.

2013, I’m going to need more rope

To sum it up, my 2013 goals are to focus on improving my current dev and GIS skills. Whatever that may entail, I’m going to go with it. I’m not too concerned about learning a new language or about what projects I plan on taking on, I just want to get better. I’ve been doing this GIS thing for over ten years now, last thing I want to do is get complacent.

Embrace Your Modules

A thousand steps to nowhere…

I think the first programming language I really started writing code in was Visual Basic 6. I had done some scripting previously in AutoCAD for simple things and I had done some VBA in Office, but VB6 was when I first wrote stuff that was taken seriously (sorta). I remember I picked up the official Microsoft Visual Basic 6 .0 Programmer’s Guide and read that beast of a book from cover to cover, thrashing it with sticky notes and bookmarks.

I was pretty proud of myself. I was tasked with building a MapObjects prototype application at work that would display some basic GIS data and pull some attribute information. I thought I was awesome, as I had this demo up and running, showing proof of concept stuff to my boss and peers. Then the feedback came in. People were impressed, they wanted to add features, change some things around to meet their needs. At first, I (foolishly) said sure, I can do that. So I went back to my desk, opened Visual Studio and stared blankly at a single Visual Basic file with hundreds of lines of code, maybe more and wondered to myself, what have I got myself into…

Not alone, I hope

I like to think I am not the only developer who started off writing all my code in a single file only to realize that when I needed to make changes or fix something, I was jumping around from a reference on line 23 to where it is changed again on like 892. (I hope I’m not the only one). In many ways, I’ll still do this when learning a new language or framework, but never on a big project, just as an exercise. Instead, I have learned over the years to break my code up into manageable pieces. Flex development was my main thing for quite a while, and I think I picked up some very good habits from that community. Smaller bits of code, broken up into modules is easier to test, easier to read (no hundreds of lines of code to swim in) and most importantly, easier to maintain.

Go modular or go…

Smarter people than myself have written about modular JavaScript development. Here is a free design pattern book to get you started. There is a great book called Learning JavaScript Design Patterns that might also interest you.

Previously, the ArcGIS JavaScript API was built on Dojo 1.6 and I was advocating the use of Require.js to build out your ArcGIS JS apps in a modular fashion. Require.js uses the AMD style of modular development. With the upgrade of the ArcGIS JavaScript API to support Dojo 1.7, some big changes came, mostly in the fact that Dojo was now using AMD style modules. I think this has left some ArcGIS JavaScript developers scratching their heads as to how to move forward, especially if the need comes up where you are required to update an older application to the new API.

Here is an example of the core change from API updgrades.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Dojo 1.6, ArcGIS API < 2.x
dojo.require('esri.tasks.Identify');

// Dojo 1.7, ArcGIS API > 3.x
define(['esri/tasks/identify'], function() {
  // ... do some stuff ...
  // Adds esri.tasks.IdentifyTask()
  // Notice I don't declare a variable name
  // for the IdentifyTask. The ArcGIS API actually
  // appends IdentifyTask to the global esri.tasks
  // object when you include it in your dependency
  // list. No need to declare a variable name in your
  // function. A lot of the API works this way.
});

Someone new to the AMD style could look at this and wonder, why in the world would I do this? I’ll quote what I think are key points from the Require.js documentation on the subject.

Clear declaration of dependencies and avoids the use of globals.
Defines a way to include multiple modules in one file.

This is sounding familiar

If you’ve read my blog (no one reads my blog) this may all sound familiar. That’s because I discussed it before. And again when the ArcGIS JavaScript 3.0 API was released. My point is, I think this is important for us as developers in the community. If you are using the ArcGIS JavaScript API for development, these are the kinds of issues you will need to do deal with.

Some resources

The ArcGIS Resource center does have some info up on migrating your development to the new Dojo 1.7. It is not incredibly comprehensive, but it’s a start.

Some may argue, “AMD is bad, CommonJS is good”, which is all fine and dandy, but seeing as we’re already using Dojo and Dojo uses AMD loading, embrace the AMD.

I would also recommend the following links to specific Dojo documentation.
Configuring Dojo with dojoConfig
Defining Modules
Modern Dojo
Using Custom AMD Modules with a CDN

If you devote some time to learning pure Dojo, I guarantee you will find yourself becoming a better ArcGIS JS developer. I have eliminated (so far) my dependencies on any third-party JavaScript libraries other than Dojo for my current projects. I have found over this past year that although many libraries offer some very nice features (Backbone), they weren’t really required for the work I do. Personally, I had set a goal for myself to be more of a minimalist in my JavaScript development. Use the right tool for the job, but you don’t always need a new toolbox.

Where’s the code?

I was getting ready to prepare a sample application to demonstrate how to build a modular application, but then I realized that just about all my samples are built in a modular fashion. Just take a glance at my github page for some examples.

Drag and Drop Editing, Because We Can.

I thought I would share what I thought was a neat little utility I made to handle dragging and dropping an image in your application onto a map to add it as a point.

A typical web editing scenario might have you use the ArcGIS JS Template Picker widget to add new data to a map. It’s a great robust widget, but I had a need to edit data and I could not use this widget, so I pretty much replicated it where I click on an image, click on the map and voila, a new point was added. At some point I was wondering, why can’t I just drag this image to the map to add it. After all, we live in a drag/swipe world these days.

I ran into some issues if the map portion of the page didn’t take up the whole browser. I knew I had to convert screen points to map coordinates, so my first thought was to use jQuery to get the screen coordinates and map position to do the conversion. For whatever reason, the jQuery method of grabbing screen points didn’t play well with this scenario. I probably just did it wrong, but I eventually just ended up using the dojo/dom-geometry module to get the positions and everything worked from that point forward. This module uses native drag/drop events and not the dojo/dnd module.

Dojo 1.8 is supposed to have introduced some nice mobile/tablet swipe functionality in their DnD module, but the ArcGIS JS API is still using 1.7, so I don’t know how well this will perform on a mobile/tablet device. I would imagine the ArcGIS JS folks are going to hold off until Dojo 2.0 (pure speculation) to update the Dojo core of the API, so I’ll revisit it then.

On the plus side, the actual DragDropHandler module is not AGS specific, so it could be used with other mapping APIs like Leaflet or OSM.

Here is the module on github. I also put a sample application in the repo that you can view here.

As an aside, this application also demonstrates my recent attempts to build pure Dojo applications, so no jQuery or Backbone, although I built it in a very Backbone-ish way.

I thought this was a pretty cool, so I felt I would share.

Quick Tip: r.js to build your ArcGIS JS Applications

esri_build

“How do I build my ArcGIS JavaScript Application using the Dojo build tools?”

I’ve seen this question come up a few times and thought I would share my experience. I’ve posted about this on twitter a couple of times, but thought it warranted it’s own posting.

A quick answer to the question above is, I don’t think you can, at least not easily. It would look like without the un-built version of the ArcGIS API, you can’t use the dojo build tools for your application. I tried following this post about a custom build. I’ve given it a shot a few times with no success, but of course if someone has and is willing to share I’m all ears. I decided to just go the simple, maybe cowardly route.

Now, before the ArcGIS API went to version 3.0 and started using Dojo 1.7, I was already using Require.js to build be applications, so I was familiar with the r.js optimization tool. After my shameful failure of trying to get the Dojo build tools to work, which by the way seemed overly complicated, but that’s just me, I decided to see if r.js would still do the trick. And sure enough, it works just fine.

I’m not going to tell you how to install r.js, but I recommend the npm install.

Here is my app.build.js file with comments and some links.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/**
* This is the build file I have started using
* to build my ArcGIS JS API 3.0 apps, which are
* based on Dojo 1.7. I used a similar build file
* when I was using Require.js, so it wasn't much different.
*
* I tried using the Dojo Build Tools, but it just seemed
* way too bloated to download the Dojo SDK, sort my files,
* blah blah blah. With r.js I can use Node NPM to
* npm install requirejs and just use the following command
* r.js -o src/js/app.build.js
* Done and done!
*
* This build file is meant to be used with r.js
* http://requirejs.org/docs/optimization.html
*
* For more details on options, you can review
* the sample r.js build file
* https://github.com/jrburke/r.js/blob/master/build/example.build.js
*/

({
appDir : "../",
baseUrl : "js",
dir : "../../release",

paths : {
"jquery" : 'libs/jquery/jquery-1.7.2.min',
"jqueryui" : 'libs/jqueryui/jquery-ui-1.8.20.custom.min',
"jquery.boostrap" : 'libs/boostrap/bootstrap.min',
"underscore" : 'libs/lodash/lodash.min',
"backbone" : 'libs/backbone/backbone-min',
/**
* This is key. Since the namespaces of dojo & esri,
* even dojox and dijit come from the ArcGIS CDN, use the
* empty: scheme so r.js doesn't try pull in these
* dependencies.
* http://requirejs.org/docs/optimization.html#empty
*/

"dojo" : "empty: ",
"esri" : "empty: ",
"text" : "empty:"
},
/**
* r.js uses uglifyjs by default.
* https://github.com/mishoo/UglifyJS/
*
* If you run r.js via java, you can use google closure.
* I tried to integrate closure, but java on my work
* machine kept punching me in the face. Stick with uglify,
* a dude on twitter told me it was faster anyway.
*/

optimize : "uglify",
/**
* This doesn't work as intended for me.
* According to docs and google groups, this
* should remove all combined files when
* optimizing a whole project
*/

//removeCombined : true,
/**
* This option will grab all the text! calls and
* place them in your optimized file to avoid
* making XMLHttpRequests to load the files
*/

inlineText : true,

/**
* This is optional, as setting the modules
* will create a combined file of all dependencies
* in the release folder. You get a single larger file
* to load rather than multiple smaller files.
* Use at your own discretion.
* */

modules : [
{
/**
* I optimze my app file, because I use
* my main file to set up my dojoConfig.
* If doing a single js file optimization,
* DO NOT include the dojoConfig file
* to be included. It will blow you up.
* Optmize the next entry point into your app.
* This is optional, you don't need modules.
*/

name: "app"
}
],

/**
* Will make your css a single line file
*/

// I had an issue in one app where this caused some issues. Didn't track it down, but only
// happened in the one app. I should look into it further. Just disable if it causes problems.
optimizeCss : "standard",
/**
* Ewww, RegEx. It's easy though,
* just include files/folders you don't want to
* get exported to your release build folder.
*/

fileExclusionRegExp : /\.(coffee|coffee~|js~|html~|css~|swp|rb|lnk)|sass|.sass-cache|build/
})

Look that over and take it in. I tried to be very descriptive with this because I’ve had to share the same file with other people on a couple of projects.

If you want to try it, I have this little app on github that you can download and try to build yourself. This will not build the dojo/esri stuff into your app, so we’re till relying on their CDN for the core library, but your code will minified just fine.

A couple of notes, I did have some issues on an app where building to a single file gave me some errors on load. I should probably document in more detail on how I fix things, but I think think adding a $(document).ready() statement to my initial require() fixed it (in my case in my main.js file). This is probably just because I’m using Twitter Bootstrap and Backbone.js which rely on jQuery. When built to a single file, I think these ready statements are more important.

Hopefully this helps some people that might be wanting to optimize their ArcGIS JavaScript builds.

Also, please if you come across a solution to this with the Dojo build tools, I’d love to hear about it.

ArcGIS JavaScript API 3.0, Dojo 1.7 and AMD Modules

Diving in

For a while now, I have been keeping my JavaScript development modular by using Require.js as I have discussed before. Require.js provides AMD module loading for JavaScript projects. If you are not familiar with AMD, take a look here. Dojo 1.7 is AMD compliant and uses require/define methods to load modules. Up until now, the ArcGIS JavaScript API has been using Dojo < 1.7 for its core. I posted before how I used Require.js to load the API into my applications. Recently, the ArcGIS JavaScript API has been updated to 3.0 and is now using Dojo 1.7 for it’s core. I was pretty excited about this, mainly for AMD modules.

As soon as I saw that 3.0 was out, I dived right in, went straight past go, updated the CDN url in one of my apps and crossed my fingers. Of course it didn’t work. So I did what any dev should do. RTFM. That gave me a little insight, but I figured there must be something in my Require.js config I need to set up, so I went to check out the How to use RequireJS with Dojo page. I know I’ve seen samples of Require.js loading Dojo modules, so I set out to hack away at it. The Require.js/Dojo template was a good read, but has since been abandoned in favor of a non-Require.js template.

Trimming it down

After some fiddling around, I found out the issue of using Require.js with Dojo 1.7 via a CDN was that you can’t and you shouldn’t. When you load Dojo via a CDN, the dojo loader will create a global define and require, negating the need to use Require.js in this case. If I was loading Dojo locally, I could continue using Require.js and load individual Dojo modules as I was initially expecting to do. Now that we know that Require.js is no longer required (pun intended), we can remove that from our upgrade path equation.

I broke it

Let’s return to the ArcGIS JS 3.0 migration page. It explains how to load custom modules while using the CDN. I tried this, and hit a snag. jQuery was broken, which broke my Backbone lib too. I use Backbone a lot. So ok, more digging. I went through this page on Using Custom Modules with a CDN. It seemed pretty straightforward, but jQuery was still broken and other modules were not working.
Part of my problem was I was trying to define my package like this.

1
2
3
4
5
packages: [
{
name: "module",
location: location.pathname.replace(/\/[^/]+$/, "") + "src/moduleFolder/moduleFile"
} ]

Where “moduleFile” is actually a JavaScript file. You don’t need to add the *.js, the require function knows what to do. The regex is needed when using the CDN so that the path will point to the server your app sits on, or else it looks in the CDN directories and you just get lots of “file not found” errors. I thought I could bypass the regex with “./src” and so on, don’t bother, do it this way, don’t be dumb like me. So I went back and read up on some more documentation. Turns out, I am dumb. Packages simply defines the path to a folder. If you want the name to point to a specific file, you need to define the main field.

1
2
3
4
5
6
packages: [
{
name: "module",
location: location.pathname.replace(/\/[^/]+$/, "") + "src/moduleFolder",
main: "moduleFile"
} ]

I fixed it

At this point, I think I’m good to go, but jQuery is still broken and I’m getting pretty pissed, but I was on a roll, so I plowed right through with various config options, then I found this article. I followed this and it worked. jQuery worked, Backbone worked, everything was working. Now I had to know why. It turns out this was the magic piece to get jQuery to work.

1
2
// Add this before first require to launch app
define.amd.jQuery = true;

There is even a page explaining about using jQuery and AMD loaders.

I have put together a sample project using ArcGIS JavaScript API 3.0, jQuery and Backbone. You can find the source on github. I add a lot of comments to the config file, but I use CoffeeScript, so look at those files for comments. To load configs, like you would inside an HTML page creating a dojoConfig, you call require passing it an object with your configs defined.

1
require({ async: true, packages: [{...}] });

Caveats and Tips

So what does all this mean to ArcGIS JavaScript developers. It means you should write your modules as AMD compliant. As of right now, a few ESRI modules work as AMD compliant, meaning you can do this.

1
2
3
define(['esri/dijit/Popup'], function(){
    return new esri.dijit.Popup({...});
});

BUT, it doesn’t work everywhere. Not all ESRI modules are AMD compliant, so for now I would suggest using the standard dojo.require() method.

If you are used to using the text plugin for Require.js to load html templates, have no fear, Dojo has you covered with dojo/text. I just had to change my modules where I called text! to dojo/text!.

1
2
3
4
5
6
7
define(['text!templates/home.html'], function(template){
    ...
});
// Became this
define(['dojo/text!templates/home.html'], function(template){
    ...
});

I tried creating an alias for this in my dojo config, but couldn’t get it to work. If someone does, I’d love to hear about it. I was able to fix this by forming my alias as a proper array or arrays in my config.
In the config, especially if you are using jQuery, async: true is an important parameter. jQuery won’t work without it. This specifies that Dojo should be loaded asynchronously. You can also use it in your require/define methods similar to the order! plugin for Require.js.

1
2
3
4
// 1 means true, 0 means false
require({async:1},['modules/myModule'], function(myModule){
    ...
});

I have not tried this method yet, but if I have a need, now I know.

Go forth and update…

The biggest hurdle for me was getting the config to work as I needed it to work. Now that I have a better understanding of how Dojo defines packages and loads them, I’ll be moving forward with the ArcGIS JavaScript API 3.x updates. Future updates when the ESRI modules become AMD compliant should be less painful. My old Require.js modules will load just fine now. Most people may not need to move on from Require.js, so you should have a clean slate to work from. Hopefully some of these tips help get you on the track to creating modular apps with the new API.

Quick tip: Loading ArcGIS JavaScript API with Require.js

In my previous post on Getting Modular with the ArcGIS JavaScript API, I discussed using a loader.js method to load your JavaScript files with Require.js. Mr. Dave Thomas pointed out in the comments about just wrapping third-party libraries using a tool like volo. See his examples at Backbone Boilerplate for more details.

If you have to wrap a library, use the amdify tool in volo or do it manually, it’s not difficult. I tried wrapping the ArcGIS JavaScript API by using curl to download it, but it didn’t work quite as expected, so now what I do is just load it once, and allow it to add its global variables.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(function() {
// Note, you must use lowercase jquery, as the ADMify'd version of backbone uses
// lowercase jquery in it's define method.
// If you just use lowercase for all aliases the way I do,
// you'll be fine.
  require.config({
    paths: {
      jquery: 'libs/jquery/jquery-1.7.2.min',
      jqueryui: 'libs/jqueryui/jquery-ui-1.8.20.custom.min',
      underscore: 'libs/underscore/underscore-min',
      backbone: 'libs/backbone/backbone-min',
      order: 'libs/require/order',
      text: 'libs/require/text',
      templates: '../templates'
    }
  });
// Load the ArcGIS JavaScript API in this initial require to get your
// app started and allow variables to go global.
  require(['app', 'http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.8compact'], function(App) {
    console.log('init app');
    return App.initialize();
  });

}).call(this);

You can see this example in a project here.

I don’t know what changes will come when the ArcGIS JS API is converted to use Dojo 1.7. It would be nice to grab just the modules needed as they are required using the AMD method, but this method of loading the API as been working fine for me lately.

Getting modular with the ArcGIS JavaScript API

Maybe it’s all the time I’ve spent using frameworks like Swiz and Robotlegs in my Flex development, but I usually strive to try and keep my code modular. Breaking it up into smaller manageable pieces, not necessarily so that I could reuse files but mostly for my own sanity.

Have you ever caught yourself starting a simple application, just keeping everything in a single file or two only to find it has grown into a beast where you get an error on line 292 but it could have carried over from something on line 5? That’s a clue you probably should look into breaking up your code. If you’re not quite sure about modular JavaScript, please go read up on it here. It’s worth it and every JavaScript developer should read it.

The first piece to this little bit I’d like to introduce is Require.js. Require.js uses the AMD (Asynchronous Module Definition) API to load JavaScript files or modules as they are called. If you have used Dojo 1.7+, you might recognize it. It’s a pretty nifty way of loading your modules. It will even work with CommonJS typed files if you need it to.  I won’t get int to AMD vs CommonJS, pick one and go with it, you’ll probably use both at some point anyway. I picked AMD. Require.js files will typically look like the following

1
2
3
4
5
6
7
define(['tools/myTool'], function(MyTool) {

var tool = new MyTool()

/// do stuff

})

Easy sauce. Simple and clean. You can read about the details on their API page.

Moving on, the next piece to modular nirvana is Backbone.js. Let me start off by saying that I was not a big fan of Backbone the first time I looked at it. It seemed to be too much trouble for little return. Then when I looked at samples of using with Require.js I was flat out ready to just say forget it. But I powered through the initial learning curve and now, I can say that Backbone.js is my most favorite little framework since jQuery. But it’s not jQuery and I’ll get to that in a second. The only hard dependency of Backbone is Underscore, which has a bunch of neat little utilities one of which is a template generator (if that’s the correct way to describe it). Backbone provides a framework to build your applications using models, views and collections. Backbone really shines when you tie your models to REST endpoinst, but that is beyond the scope of this little intro. It does not do DOM manipulation, but the views components can use jQuery to bind to a view that is rendered on the DOM. Once you start using it, it will kick in and you’re going to want to send me lots of beer for encouraging you to use it.

The next step, which took the most brain matter for me to really kind of tear apart and piece back together to make sense of it was on how to use these tools together with the ArcGIS JavaScript API. Well, as usual with the internet there’s a page for that. I followed this model to build my first test applications. That link goes over in detail on how to load external scripts and set up your bootstrapping for your application. Basically what you end up doing is creating aliases to library paths and use the aliases.

So you can follow along, I placed the code for this article on github. Here is my run.js bootstrap file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
#This is essentially where you do
#your bootstrapping for your application.
#Define aliases for the paths to your
#JavaScript libraries or other folders
#you may use.
*/


require({
  baseUrl: 'javascripts',
  paths: {
    loader: 'libs/backbone/loader',
    jQuery: 'libs/jquery/jquery',
    Underscore: 'libs/underscore/underscore',
    Backbone: 'libs/backbone/backbone',
    dojo: 'libs/esri/dojo',
    templates: '../templates'
  },
  cach: {}
}, ['main']);

The interesting stuff then happens in the loader.js file.

1
2
3
4
5
6
7
8
define(['order!http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.7', 'order!libs/jquery/jquery.min', 'order!http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js', 'order!libs/underscore/underscore-min', 'order!libs/backbone/backbone-min'], function() {
  return {
    Backbone: Backbone.noConflict(),
    _: _.noConflict(),
    $: jQuery.noConflict(),
    dojo: dojo
  };
});

This loader file defines where your libraries come from, local files or external, doesn’t matter. When the files are loaded, the loader will return an object that contains a reference to the libraries like Backbone, jQuery or dojo. The link above that I based this off of explains these concepts in more detail, the important thing to know is that the loader loads libraries. One thing to note is that the only time you ever have to reference the ESRI API url. When the API is loaded anywhere, it goes global, so dojo is available throughout your whole application now. There is a special case for this, but I won’t go into detail on that, if it happens to you, you’ll know.

I know this seems like a lot of upfront effort, but it’s really not so bad when you get the idea of what is happening. Once I’ve bootstrap the application, the ‘main.js’ file gets loaded. I use this file to make a couple of tweaks to the way Underscore does it’s templating and I start the application.

1
2
3
4
5
6
7
8
9
define(['require'], function(require) {
  return require(['app', 'Underscore'], function(app, _) {
    _.templateSettings = {
      interpolate: /\{\{(.+?)\}\}/g,
      evaluate: /\{\#(.+?)\}\}/g
    };
    return app.start();
  });
});

I won’t go into detail on the app.js file, but I do want to move on to some specific Backbone stuff. The sample application I have put together shows a map of the United States. There is a sidebar that list the name o each state. Clicking on a name will zoom you in to that state on the map. Pretty straightforward operation.

Here is my Backbone model for the state item.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
define(['Backbone'], function(Backbone) {
  var State;
  return State = Backbone.Model.extend({
    initialize: function(state) {
      this.state = state;
      return {
        defaults: {
          name: "",
          graphic: null,
          map: null
        }
      };
    },
    zoom: function() {
      var extent;
      this.state.map.graphics.clear();
      this.state.map.graphics.add(this.state.graphic);
      extent = this.state.graphic.geometry.getExtent();
      return this.state.map.setExtent(extent, true);
    }
  });
});

This model has a reference to a graphic and the map. It’s not a copy, just a reference, so it’s not like you’re using up extra memory here. This allows the model to have it’s own zoom function to zoom in to itself on the map. I use this technique a lot when I need to populate a list with items from a map, click on the list and zoom to it. It’s a pretty straightforward function and this pattern simplifies it for you.

But wait, you don’t need to interact directly with the model, there’s a Backbone collection for that.

1
2
3
4
5
6
7
8
9
10
11
12
define(['Backbone', 'models/State'], function(Backbone, State) {
  var StateCollection;
  StateCollection = Backbone.Collection.extend({
    model: State,
    zoomByCid: function(cid) {
      var state;
      state = this.getByCid(cid);
      return state.zoom();
    }
  });
  return new StateCollection;
});

The cid is a unique id that the collection will assign to each model that is added to it. You can use this cid in the collection find the correct model and access it’s zoom function that we assigned to it. But how do I interact with the collection? Bear with me a second. If this seems a little confusing, don’t worry, it took me a while to kind of grasp how the pieces all fit together.

We can access the collection from our view.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
define(['jQuery', 'Underscore', 'Backbone', 'collections/StateCollection', 'text!templates/forms/StateListView.html'], function($, _, Backbone, stateCollection, viewTemplate) {
  /*
            # This list view will
            # handle rendering and events
            # of the sidebar list
  */

  var ListView;
  ListView = Backbone.View.extend({
    el: $("#sidebar>ul"),
    tagName: "ul",
    initialize: function() {
      return this.collection = stateCollection;
    },
    events: {
      "click a": "clicked"
    },
    clicked: function(evt) {
      var cid;
      evt.preventDefault();
      cid = $(evt.currentTarget).data("id");
      return this.collection.zoomByCid(cid);
    },
    render: function() {
      var data, template;
      data = {
        states: this.collection.models,
        _: _
      };
      template = _.template(viewTemplate, data);
      $(this.el).html("");
      return $(this.el).append(template);
    }
  });
  return new ListView;
});

This view holds a reference to the collection that we are using. When the view is rendered, we use Underscore.js to load a template and render it to the view.

1
template = _.template(viewTemplate, data);

There are a couple of things happening in the view. First you’ll notice this line in out define.

1
'text!templates/forms/StateListView.html'

This will load an html file that has a little function to load each data from each model into the view. This view also handles the events of the view using jQuery. When an item in the list is clicked, it will find the cid we discussed earlier by searching for the data id attribute tag we assigned in the template and use the collection function we made called zoomByCid() to zoom to that location. It all fits together in a neat little package.

Just to give you an idea of what it looks like, here is template.

1
2
3
4
5
{# _.each(states, function(state) { }}
<li>
  <a data-id='{{ state.cid }}' href='#'>{{ state.get("name") }}</a>
</li>
{# }); }}

This uses an Underscore utility function to iterate the array of models and render each one to a list item and passes model information into the anchor. If you’ve done jQuery templating this look very familiar to you. As a matter of fact you could use jQuery templates in the view if that’s what you’re comfortable with.

You can see a working demo of this application here.

Ok, I think I’ve covered a the basics of how you might use Require.js and Backbone.js with the ArcGIS JavaScript API. I know this might all seem like a lot of work, but imagine building a more complicated application with multiple views, maybe a couple of more collections and you can see how this pattern can simplify that task for you. There is definitely more to Require.js and Backbone.js that you could learn about and I encourage you to look up more examples. For example, I recently used Backbone.js with .NET MV3 REST endpoints and the ArcGIS JavaScript API and the workflow is incredibly simple. Backbone.js shines with REST endpoints.

By the way, the source for this example uses CoffeeScript and Sass/Compass for css. Don’t worry about that, I’ll get to Sass/Compass stuff later.

I hope I was able to introduce you to some tools that you can add to your development toolbox and use wisely. Go forth, and make cool shit.

Simplify dev (for the ArcGIS developer): Part 2

In part 1 of this series, I told you to abolish your IDE and take up the torch of the text editor. Now I’m going to challenge you to burn your code to the ground. Ok, not quite…

Simplify your code

I’ll make this real simple. A lot of people hate JavaScript for various reasons. Mostly because it’s too damn flexible for their liking. That’s also it’s greatest strength.
Update (Dec, 2012): I have since changed my personal stance on CoffeeScript. I still enjoy writing CoffeeScript for my personal projects. However, I have found that when working in a team environment, it is not always the best choice. Your team may not know CoffeeScript, may not want to learn it or don’t have the time to learn it. They may just need to do simple integration and maintenance, so there is no need to add an extra layer of abstraction to their workload. I still think CoffeeScript has its merits, but it is no longer for me.
So today, I’m going to encourage you to stop writing JavaScript. Just stop it, forget it, move on to something else. Move on to CoffeeScript. People that love Ruby, love CoffeeScript. I say that features that make Ruby so appealing are what should attract you to CoffeeScript. There is no “var” in CoffeeScript, nor is there any semicolons or excessive brackets. I enjoy the readability and I can just get my ideas across faster when writing in CoffeeScript. And CoffeeScript compiles to JavaScript that is probably better than you would normally write on your own. I’m not going to teach you how to write CoffeeScript, there are much better resources for that. I am going to show you an example of a simple mapping application written using CoffeeScript and the ArcGIS JavaScript API.

Getting Started

To install CoffeeScript, you’re going to need to install Node.js. If you’re on Linux or a Mac, you have an easy path ahead of you, you probably already have both installed. If you’re on Windows, there is now a Windows installer for Node.js with npm. You might still run across some issues, but I have high hopes.

For this example, we’re going to stay basic and use a sample from the ArcGIS JavaScript API samples pages. To make it interesting, we’ll use the Identify with Popup sample. The sample is pretty straightforward and shows the basics of how you would initialize your map and use a task, in this case IdentifyTask to perform some action. First off, part of the issue I have seen a lot on the forums and with beginners to the ArcGIS JavaScript API, is they will take these samples as-is and try to build production apps from them. They’re samples. When you find your users requesting new features or changes, you’re going to find yourself in the deep end when you try to integrate functionality from other samples into your now production application. Step back, review them, learn them, let them soak in.

Stop putting code in your markup

Now, I’m going to show you the first step to making your application simpler and easier to maintain. Separate your JavaScript from your HTML. To quote Tony Stark, “That’s how Dad did it, that’s how America does it, and it’s worked out pretty well so far.” This follows a basic philosophy I picked up when first treading into web development waters. HTML is markup, CSS is style, and JavaScript is function, never shall the three ever meet. That’s not really strict, as your code will mingle and fiddle with your DOM and styles all the time, but when you are starting your application, this is a pretty good starting point. So first off, take the JavaScript out of the HTML, save it in a file called main.js or app.js, there is no strict rules here. Refer to it like any other file.

1
<script type="text/javascript" src="javascripts/main.js"></script>

That’s step one. In a later posting, I’ll discuss on further simplifying the separation of your markup from your style and code. Now, I’m just going to throw this out there to get things going. Here is the CoffeeScript version of the JavaScript code in the sample we are working with.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
dojo.require "dijit.layout.BorderContainer"
dojo.require "dijit.layout.ContentPane"
dojo.require "esri.map"
dojo.require "esri.dijit.Popup"

dojo.addOnLoad ->
  initExtent = new esri.geometry.Extent
    xmin: -9270392
    ymin: 5247043
    xmax: -9269914
    ymax: 5247401
    spatialReference:
      wkid: 102100
 
  lineColor  = new dojo.Color [255,0,0]
  fillColor  = new dojo.Color [255,255,0,0.25]
  lineSymbol = new esri.symbol.SimpleLineSymbol esri.symbol.SimpleLineSymbol.STYLE_SOLID, lineColor, 2
  fill       = new esri.symbol.SimpleFillSymbol esri.symbol.SimpleFillSymbol.STYLE_SOLID, lineSymbol, fillColor
  popup      = new esri.dijit.Popup { fillSymbol: fill }, dojo.create "div"

  map = new esri.Map "map",
    infoWindow: popup
    extent: initExtent

  basemap = new esri.layers.ArcGISDynamicMapServiceLayer "http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"
  map.addLayer basemap

  landBaseLayer = new esri.layers.ArcGISDynamicMapServiceLayer "http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/BloomfieldHillsMichigan/Parcels/MapServer",
    opacity: 0.55
  map.addLayer landBaseLayer

  dojo.connect map, "onLoad", (_map_) ->
    identifyTask                  = new esri.tasks.IdentifyTask "http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/BloomfieldHillsMichigan/Parcels/MapServer"
    identifyParams                = new esri.tasks.IdentifyParameters()
    identifyParams.tolerance      = 3
    identifyParams.returnGeometry = true
    identifyParams.layerIds       = [0, 2]
    identifyParams.layerOption    = esri.tasks.IdentifyParameters.LAYER_OPTION_ALL
    identifyParams.width          = _map_.width
    identifyParams.height         = _map_.height

    dojo.connect _map_, "onClick", (evt) ->
      identifyParams.geometry = evt.mapPoint
      identifyParams.mapExtent = _map_.extent

      deferred = identifyTask.execute identifyParams
      deferred.addCallback (response) ->
        dojo.map response, (result) ->
          feature = result.feature
          feature.attributes.layerName = result.layerName
          if result.layerName is "Tax Parcels" then feature.setInfoTemplate new esri.InfoTemplate "","${Postal Address} <br/> Owner of record: ${First Owner Name}"
          else if result.layerName is "Building Footprints" then feature.setInfoTemplate new esri.InfoTemplate "", "Parcel ID: ${PARCELID}"
          feature
      _map_.infoWindow.setFeatures [ deferred ]
      _map_.infoWindow.show evt.mapPoint

    dojo.connect dijit.byId("map"), "resize", _map_, _map_.resize

Now take a second to review that and see if you can follow it. First thing you may notice is the lack of parentheses or brackets. it might seem a little off at first, but the readability is greatly increased. Whitespace is king.

Would you like some sugar with that?

The main thing to remember when writing CoffeeScript is that to write a function, you write the following to define a function.

1
(value) ->

This interprets to a JavaScript function.

1
function(value) {}

Once you get that basic down, you’re most of the way there.
Another idiom of CoffeeScript that differs slightly from JavaScript is the form

1
if something is mything then do yourthing

You’ll see bits of this kind of syntactic sugar throughout CoffeeScript. It does exactly what it says in plain english. Simple and elegant.

Let’s look at another interesting line having to do with executing a method.

1
lineColor = new dojo.Color [255,0,0]

You get the idea of what is happening, but where are the parentheses? You don’t need them. You know you’re calling a method, the CoffeeScript compiler knows you’re intention, so it’s not needed. The equivalent JavaScript is below.

1
lineColor = new dojo.Color([255,0,0])

The parentheses are nothing more than a visual cue to the user, but eliminating them makes for simpler code. I would suggest you read some CoffeeScript tutorials to get familiar with the lack of parentheses. There are some caveats where if you do chaining of methods like you might with jQuery, then you will need to use parentheses.

1
$(".help").click (evt) -> console.log 'clicked'

Or when you need to just call a method with no parameters.

1
query = new esri.tasks.Query()

Another bit of syntactic sugar of CoffeeScript is in defining objects. You don’t need brackets, you just need white space.

1
2
3
4
5
6
7
  initExtent = new esri.geometry.Extent
    xmin: -9270392
    ymin: 5247043
    xmax: -9269914
    ymax: 5247401
    spatialReference:
      wkid: 102100

The above CoffeeScript code is equivalent to the following JavaScript code.

1
2
3
4
5
6
7
8
9
10
var initExtent;
initExtent = new esri.geometry.Extent({
  xmin: -9270392,
  ymin: 5247043,
  xmax: -9269914,
  ymax: 5247401,
  spatialReference: {
    wkid: 102100
  }
});

There is much more syntactic sugar and CoffeeScript goodness that I won’t go over. I’d suggest some tutorials of a book to get the most out of it. I just wanted to introduce some simple ways of simplifying your “busy” JavaScript with simplistic, yet effective CoffeeScript.

Sweet coffee to bitter joe

You might be asking yourself what to do with this awesome CoffeeScript file. After all, you can’t very well just use that in your application. If you installed Node.js and CoffeeScript properly, you should be able to use this command

1
coffee --compile main.coffee

This will produce a main.js file. You can review the output below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
dojo.require("dijit.layout.BorderContainer");

dojo.require("dijit.layout.ContentPane");

dojo.require("esri.map");

dojo.require("esri.dijit.Popup");

dojo.addOnLoad(function() {
  var basemap, fill, fillColor, initExtent, landBaseLayer, lineColor, lineSymbol, map, popup;
  initExtent = new esri.geometry.Extent({
    xmin: -9270392,
    ymin: 5247043,
    xmax: -9269914,
    ymax: 5247401,
    spatialReference: {
      wkid: 102100
    }
  });
  lineColor = new dojo.Color([255, 0, 0]);
  fillColor = new dojo.Color([255, 255, 0, 0.25]);
  lineSymbol = new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, lineColor, 2);
  fill = new esri.symbol.SimpleFillSymbol(esri.symbol.SimpleFillSymbol.STYLE_SOLID, lineSymbol, fillColor);
  popup = new esri.dijit.Popup({
    fillSymbol: fill
  }, dojo.create("div"));
  map = new esri.Map("map", {
    infoWindow: popup,
    extent: initExtent
  });
  basemap = new esri.layers.ArcGISDynamicMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer");
  map.addLayer(basemap);
  landBaseLayer = new esri.layers.ArcGISDynamicMapServiceLayer("http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/BloomfieldHillsMichigan/Parcels/MapServer", {
    opacity: 0.55
  });
  map.addLayer(landBaseLayer);
  return dojo.connect(map, "onLoad", function(_map_) {
    var identifyParams, identifyTask;
    identifyTask = new esri.tasks.IdentifyTask("http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/BloomfieldHillsMichigan/Parcels/MapServer");
    identifyParams = new esri.tasks.IdentifyParameters();
    identifyParams.tolerance = 3;
    identifyParams.returnGeometry = true;
    identifyParams.layerIds = [0, 2];
    identifyParams.layerOption = esri.tasks.IdentifyParameters.LAYER_OPTION_ALL;
    identifyParams.width = _map_.width;
    identifyParams.height = _map_.height;
    dojo.connect(_map_, "onClick", function(evt) {
      var deferred;
      identifyParams.geometry = evt.mapPoint;
      identifyParams.mapExtent = _map_.extent;
      deferred = identifyTask.execute(identifyParams);
      deferred.addCallback(function(response) {
        return dojo.map(response, function(result) {
          var feature;
          feature = result.feature;
          feature.attributes.layerName = result.layerName;
          if (result.layerName === "Tax Parcels") {
            feature.setInfoTemplate(new esri.InfoTemplate("", "${Postal Address} <br/> Owner of record: ${First Owner Name}"));
          } else if (result.layerName === "Building Footprints") {
            feature.setInfoTemplate(new esri.InfoTemplate("", "Parcel ID: ${PARCELID}"));
          }
          return feature;
        });
      });
      _map_.infoWindow.setFeatures([deferred]);
      return _map_.infoWindow.show(evt.mapPoint);
    });
    return dojo.connect(dijit.byId("map"), "resize", _map_, _map_.resize);
  });
});

Also, the source code for this sample can be found here.

By the way, Net.tuts+ has a great little intro to CoffeeScript that I would recommend, along with the draft of the Little Book on CoffeeScript which is a great primer. I would also highly recommend picking up the published copy. Another great resource to play with is js2coffee.org.

The brew of heavens cafe

Phew, that might be quite a bit to take in. After all that, you might be asking yourself why you would even bother with CoffeeScript. I would argue that CoffeeScript provides a simpler approach to writing solid JavaScript. It’s not as apparent in this simple example, but many times it can obfuscate some tricky JavaScript funkiness, as in dealing with the “this” keyword in some callback methods. You can also declare classes in CoffeeScript like so.

1
2
3
4
Class MyLayerUtil
    constructor: (@lyrs) ->
    allUrls: ->
        urls = (lyr.url for lyr in @lyrs)

I don’t know about you, but I think that’s pretty nice and clean. CoffeeScript is still fairly new, but there is a great community of developers using it everyday. It’s included in Rails 3.x, so it’s not exactly a “not ready for production” tool. People are using it and loving it.

In the next posting, I’m going to cover some more interesting tools to help you simplify your web development workflow. I’ll go over how to simplify your markup and style.