Titanium Community Questions & Answer Archive

We felt that 6+ years of knowledge should not die so this is the Titanium Community Questions & Answer Archive

Android cannot find my global variable within a commonjs module

To organize my project better, I made a global object that contains settings/global functions/etc. and I included that in my app.js file.

global_var.js

var GlobalVar = {};
GlobalVar.font = 'foo';
GlobalVar.bar = function() {return true;}

Then in app.js I include this file.

Ti.include('global_var.js');

I then create a commonjs module for a window and in that I reference the GlobalVar variable.

menu.js

... code to create window ...

var label = Ti.UI.createLabel({
        text : 'Foo Label',
        font : {
            fontFamily : GlobalVar.font,
            fontSize : 24
        });

Everything works great in iOS, but when I try to run on the Android emulator I get an error for "Uncaught ReferenceError: GlobalVar is not defined". Why can Android not see the global variable?

Titanium SDK 1.8, Android 2.2.3 V8

— asked January 4th 2012 by Matt Johnston
  • android
  • commonjs
  • global
0 Comments

4 Answers

  • Accepted Answer

    To copy-paste myself :)

    In Titanium's CommonJS implementation, variables defined in global scope cannot be referenced from module's scope.
    That is, CommonJS module creates new JS context (like iframe in browser environment), so even if you do something like change of native prototypes like "String.prototype" (String.prototype.doSomething = function() {}), that won't be reflected in module scope (typeof "".doSomething === "undefined").
    Now, is that a good thing or a bad thing can be discussed. :)

    — answered January 4th 2012 by Ivan Škugor
    permalink
    3 Comments
    • Dont get me wrong using commonjs modules is the way forward; however having the ability to define globals I miss alot; I mean alot; its bad practice but sometimes to make development 100 fold easier I want the ios broken implementation every day of the week;

      — commented January 30th 2012 by richard hooker
    • Yeah, I agree. :)

      — commented January 31st 2012 by Ivan Škugor
    • Use the properties API..

      — commented September 19th 2012 by Mark Henderson
  • On Android you cannot have variables outside the current commonJS scope. From what I understand, the behaviour you are seeing is actually an 'error' in the iOS javascript implementation (at least that's what I read on the boards in a previous post).

    — answered January 4th 2012 by Ray Belisle
    permalink
    0 Comments
  • a solution can be found at www.thewarpedcoder.net shows how to create a global variable module.

    Hope this helps.

    T…

    — answered January 4th 2012 by Trevor Ward
    permalink
    4 Comments
    • Trevor, I've been trying to implement a similar solution, and it works fine on Android but fails in iOS. I have a window that is opened with the "url" property, which tries to require('Globals'), but that ends up reloading the Globals.js file (another require-d module already did a require('Globals') call), contrary to Appcelerator's documentation.

      Does anyone know why this happens or how to prevent it?

      — commented January 5th 2012 by Shawn Lipscomb
    • Monkey-patch it :)

      — commented January 5th 2012 by Ivan Škugor
    • Hi Shawn sorry not got back to you but it's been a busy day.

      OK sorry Ivan but Shawn please don't monkey patch this it is not required nor is it a sensible solution.

      The solution is not to load a window with the URL property. The issue you have is that when you load using the URL it actually uses an new context of the JavaScript interpreter so it will actually load any required files into memory again.. This is not a bug but is well documented that using a URL load unless you have a very very specific reason to is not recommended.

      I know the kitchen sink is written that way, but they do have a specific reason to.

      Hope this resolves the confusion on this that titanium is actually performing as it should in the way you are using it. To fix it will require you to change the application architecture.

      T.

      — commented January 5th 2012 by Trevor Ward
    • I think it's a bug, but I'm not sure on what side. :)

      The problem here is that iOS re-requires modules in new URL-based context, while Android does not. CommonJS specification does not define this behavior (as far as I know).

      While I agree with you that real solution is to re-write application so it does not use URL-based windows, sometimes re-writing is not simple thing to do. Monkey-patch so that module is not re-required in new context is quick and dirty solution (sometimes it's better to have any solution, than no solution).

      — commented January 6th 2012 by Ivan Škugor
  • Well, good to know it's not possible then.

    What is a good way to try to achieve global variables between multiple modules? I might just drop commonjs because it has caused me more problems than benefits.

    — answered January 4th 2012 by Matt Johnston
    permalink
    2 Comments
    • You know, I'm not really sure about globals except to see if Titanium.App.properties would meet your needs. I don't use globals in my code, but commonJS has really helped nailing down memory problems and (to date for me at least) has been MUCH better than some of the other approaches I have seen for apps.

      — commented January 4th 2012 by Ray Belisle
    • Write them as CommonJS module and "require" them in multiple different modules.

      — commented January 4th 2012 by Ivan Škugor
The ownership of individual contributions to this community generated content is retained by the authors of their contributions.
All trademarks remain the property of the respective owner.