Callbacks Are Your Friend, Events aren’t too bad either

Magnificent colorful vertical shot of a slot canyon in Lower Antelope Canyon in Arizona USA.

We all know from reading the Appcelerator wiki about Javascript best practices that global variables and polluting the global namespace are no-nos when writing good, maintainable code. However, we also know that old habits are hard to break – we are writing the code, we need “this” value set? Who cares?! Just create a global and be done with it!

The problem with this approach is that it will eventually come back to bite us; we will forget about the global variable, someone else won’t be aware of it and, consequently, they will create some other way to get the same information. Worst of all – it won’t always work.

Three notes we need to write on bright yellow stickies and attach to our monitor:

  • We are going to write modular code (from now on, at least)
  • Event-based programming is a good thing
  • Global variables should be used only as a last resort

Get The Location

So, first, what is the problem? Getting the user’s current location!

This will happen asynchronously, and the UI element we need to update is in another file. Of course, this is modular code!

We know that the API call Titanium.Geolocation.getCurrentPosition uses a callback to let us know when it has found a location.

Put it somewhere useful

Now we could create a global variable outside of the callback and use that to get the information.

but that only helps if the UI element we need to update is in the same JS file as the callback. That’s not possible when writing modular code. Also, we definitely should not have UI code mixed in with the geolocation logic.

Put it somewhere better using an event listener

So what are we going to do? The first thing is to get rid of the global variable and fire an event to indicate that a location has been successfully received.

So now, anywhere in the application when we need to get the location information, we can create a listener to get the coordinates delivered in the event payload. This is nice; no globals necessary at all!

But there is another way; use a callback within the callback

Let’s pass in a function to call when the device has finished getting the location. Along with firing the event, we will call the function passed in as a parameter with the coordinates we received from the device.

Somewhere else in our code we need to get the location and update the UI element with the information.

Modules are GOOD! That’s what Kevin said!

Kevin Whinnery: Write Better JavaScript: video | slides

OK, now we have the GPS code in an include file, separated from the UI, and we can make calls from anywhere and get the location information from either an event or a callback. BUT we are not quite yet there – what about modules and CommonJS and all that “requires” stuff?

We want to be good Appcelerator citizens, producing code that is more code-strong than kitchen-sink! After all, the KitchenSink only exists to demonstrate API functionality, and not to act as a best-practice example.

Let’s convert our location file into a module; just add “exports” before the function name to make it public.

In our ui.js file, where we created the window, we need to load the module containing the currentLocation function. In the complete example, we have named the file “maps.js”, so we need to add the require statement.

Remember: don’t include the “.js” extension when using require; it’s not needed.

var maps = require('lib/maps');

Then when you call the method it looks like this:

// do the callback to get current location

Here is the complete ui.js file


Using callbacks and events are good for your code; it encourages decoupling and better separation of business logic from the presentation layer. From now on, we will be strongly encouraging a more modular approach to application development, and this will be reflected in all the content we will be bringing you in the near future.

Keep coding strong!

The Code


  1. How does modularity work in the context of modules, more specifically if I have a module that I would like to break up in parts can I do Ti.include as usual in the code that’s being required and will it end up in the module context or the global context?

  2. I do have few remarks.

    App-level events are dangerous same as global variables. You did emulate namespaces with their names (‘location.updated’) so you did solve some problems. But the other problem (beside other possible problems) is that app-level event handlers always remain in application, even when component that uses that event is no longer existing. That event handler function holds reference to “label” component, so it is questionable will that label ever be released from memory.

    Also, if you want to even more decouple components, you should separate window and label creation logic, from “updating label’s text with gps location” logic.

    I hope my insights are valid. 🙂

  3. You’re monkey-patching the require-statement and you don’t think this is even worth mentioning in the blog-post? wow…

    could we please get a few words about that? Some explanation and reasoning would be nice

  4. Thanks for this, that’s a big help. I look forward to a lot more posts like this.

    Karl, where’s the monkey-patching here, that’s the standard “require” function being used isn’t it?

  5. Karil, just looked at the code on GitHub. You’re right. Oh well, it’s stil a very useful blog post!

  6. @karl @Richard I apologize for the lack of explanation for the monkey patch, the source has been updated in github.

    The quick answer is that the current implementation of requires in appcelerator does not match the spec so the patch was needed.

  7. @Richard thanks for the comment on the post, there will be more good stuff like this coming from us all here!

    @Ivan you are correct about the memory, but since the window is the main app window, it wont necessarily cause a leak since when the window is closed the app closed.

    one possible solution is to remove the event listener when the window closes, that will allow the label to be garbage collected

  8. @Aaron another nice tutorial, keep them coming Appcelerator.

    Re CommonJS modules – I don’t know what other Ti developers are doing, but I’m waiting for them to be working 100% before I move away from the Ti.Include / revealing module pattern / factory / Tweetanium approach I’m using.

  9. @Aaron: Thanks for the tutorial.
    I am seeing that you are using Ti.App.fireEvent from inside a CommonJs module, which is exactly the way I wanted to implement communication between UI and Model in an app I’m working.
    However, it doesn’t seem to work for me.
    I don’t see that the events are fired at the console, and are also not received in the context where I am subscribing to the event.
    I am using SL and XCode 4.0 in one machine, Lion and Xcode 4.2 on another.
    Is it supposed to be like that or is it just a bug?

Comments are closed.