Tag Archives: javascript

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.

Quick Tip: CSS Filters and your ESRI Tiles

OSM Layer (grayscale css)

I was playing around with some css properties recently while working on a project to try and make working with the OSM layer in the ArcGIS JS API a little nicer. The service already looks good, but I kept wishing I had it as a grayscale. Then I found this.

The way I did it was to give my osm layer an id.

1
2
3
osm = new esri.layers.OpenStreetMapLayer({
id: 'osmLayer'
});

The HTML element that gets created for the layer will be map_LAYER_ID, so map_osmLayer in this case.
Then I just apply the css to all img tags in this div.

1
2
3
4
5
6
#map_osmLayer img
{
filter: url(filters.svg#grayscale) !important; /* Firefox 3.5+ */
filter: gray !important; /* IE5+ */
-webkit-filter: grayscale(1) !important; /* Webkit Nightlies &amp; Chrome Canary */
}

And voila!

OSM Layer: Default css

 

OSM Layer: grayscale(1);

 

FYI: I know grayscale as used in the CSS I posted works in all browsers (even IE8), but I can’t guarantee other filters will work in IE.
This comes in really handy, so as only this layer is impacted by the css, my own data can “pop” a bit more. There’s more you can do with these fun filters!

 

OSM Layer: hue-rotate(50deg);

 

OSM Layer: brightness(-10%) sepia(100%);

 

OSM Layer: invert(100%);

 

Of course you can mix and match these css styles, so experiment with them to see what kind of interesting effects you can plug into your maps.

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.

CoffeeScript, Visual Studio and Sublime Text 2

I had previously written about simplifying your dev environment. Most of the day to day work that I do, I can manage with vim just fine. But I also use Visual Studio quite a bit for ASP/MVC3 and (don’t laugh) Silverlight. So when I do web dev in Visual Studio, I like to set up my environment in a way that makes me effective and productive. I never really thought about this process until I started doing some pair-programming and had to share this convoluted information with another human being. I’m going to do this step-by-step, so there’s no confusion (please don’t get confused).

1: MVC 3

Of course you’ll need Visual Studio 2010. In my case, I work mainly with ASP.NET MVC 3 when using Visual Studio, so be sure to install that here.

2: Mindscape Workbench

You can get Mindscape Workbench here. It’s a great plugin for Visual Studio that allows you to create CoffeeScript files as well as Less/Sass files. We’ll also need to install CoffeeScript and Sass/Compass for this to work. You can read more about the plugin from Scott Hanselman here. One drawback it has is that there is no intellisense for CoffeeScript files. This is the next step.

3: Sublime Text 2

This is not a required step, you could just as easily use vim or some other text editor, but I wanted to set things up in a somewhat easier to use environment for someone that doesn’t care about vim power. Download it here. Leave it alone for now, we’ll come back to this later.

4: Git

Now the fun begins, install Git for Windows from here. From here on out, I recommend using the Git Bash shell for simplicity sake. Now the tricky part is working with these command line tools behind a proxy. If you’re lucky, you don’t work behind a proxy, if you’re not, these command line tools will not automatically be aware if your internet settings, so you need to manually set them up. You can use the following command or git as discussed in this Stackoverflow question.

git config –global http.proxy http://proxy_host:port

5: Ruby

This is a simple one, install Ruby from here. The Ruby installer comes with gem. Once again, per instructions here and here, we may need to set up gem behind a proxy. Run this command before using gem.

set HTTP_PROXY=http://proxy_host:port

This should set HTTP_PROXY for this current bash session, so you’ll do it each time you reopen bash before running gem. I tried setting up a permanent environment variable for this, but it interfered with my internet connection. You may have better luck. I could have sworn there was a config file you could create that gem could read for proxy info, but can’t remember it.

6: Node.js

Simple enough these days, use the windows installer for Node.js and you should be all set. Before the windows installer, this process sucked, I would say run Linux in a Virtual Box and spare the stress. Thanks Node devs for making this a clean process for Windows guys. The installer comes with npm, so if you need to work behind a proxy, read this and do the following.

npm config set proxy http://proxy_host:port
npm config set registry “http://registry.npmjs.org/”

7: CoffeeScript

Now you can install CoffeeScript, finally!

npm install -g coffee-script

Now you the Mindbench plugin for Visual Studio can compile your Less/Sass files.

8: Sass/Compass

Install Compass per these instructions.

gem install compass

9: CoffeeScript bundle for Sublime Text 2

Get the CoffeeScript bundle here. Sublime Text 2 can use Textmate bundles, so this works great. On Windows 7, you are looking for $HOME/AppData/Roaming/SublimeText 2/packages/, where $HOME is your user documents and settings folders. Turn on the ability to show hidden files and folders if you don’t see the AppData folder. Run the following command.

git clone git://github.com/jashkenas/coffee-script-tmbundle CoffeeScript

Add the ability to build the CoffeeScript files per this link. Open the CoffeeScript/Commands folder and look for a file named CoffeeScript.sublime-build. Make sure it looks like this. I did not need to have the “path” option for it to work for me.

{
“cmd”: ["coffee.cmd","-c","$file"],
“file_regex”: “^(…*?):([0-9]*):?([0-9]*)”,
“selector”: “source.coffee”
}

Now when you edit a *.coffee file in Sublime Text 2, you can use ctrl+b to build and save the file at the same time.

10: Take it for a spin

At this point, start up Visual Studio, start a new MVC 3 Web project. Add a new item, and you should have the option to add CoffeeScript files.
Right click the CoffeeScript file -> Open With, choose “Sublime Text 2″, if not an option, browse to the sublime.exe in Program Files\Sublime Text 2. Set it as the default and now all *.coffee files will open in Sublime Text 2 when double-clicked in Visual Studio. Again, press ctrl+b in Sublime Text 2 to build and save the *.coffee files and you should be good to go.

Whew…

Ok, I know this whole process seemed a little long, but I find it to be worthwhile in my dev workflow. The trickiest part for me was getting everything working behind a proxy. After I had to do this on a couple of machines and asked to explain it, I thought I should document this somehow. Many of the search results out there are also written specific to OS X and Linux users, so there are little bits here and there that took some translating to Windows, not much, but slight nuances like installing the CoffeeScript bundle. I hope everything works for you. If you run into to trouble, I’ll see if I can help, but some Google-fu worked when I got stuck.

I did not cover each tool in much detail, like how to use git or the benefits of npm and gem. I would encourage you to read on these subjects further if you are interested. I would like to state that Node.js and Ruby are more than development languages (Ok, Node is a library, give me a break), but they open up a whole world of tools that you can use in your day to day development, like testing, building of your web applications.

I hope someone finds this information useful. It took me hours to figure out when I first started it some time ago, so hopefully I saved you some time.

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.