Appcelerator Blog

The Leading Resource for All Things Mobile

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

0 Flares 0 Flares ×
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. [gist id=”1270873″]

Put it somewhere useful

Now we could create a global variable outside of the callback and use that to get the information. [gist id=”1270894″] 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. [gist id=”1270930″] 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. [gist id=”1271028″] Somewhere else in our code we need to get the location and update the UI element with the information. [gist id=”1271056″]

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. [gist id=”1271113″] 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 [gist id=”1271130″]


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
0 Flares Twitter 0 Facebook 0 Google+ 0 LinkedIn 0 Email -- 0 Flares ×


  1. Karl Å

    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. Ivan Skugor

    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. Karl Å

    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. Richard Shergold

    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. Richard Shergold

    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. Aaron Saunders

    @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. JeffAtStepup

    @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. Richard

    @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.

Sign up for updates!

Become a mobile leader. Take the first step to scale mobile innovation throughout your enterprise.
Get in touch
computer and tablet showing Appcelerator software
Start free, grow from there.
0 Flares Twitter 0 Facebook 0 Google+ 0 LinkedIn 0 Email -- 0 Flares ×