0

I have a single html page phonegap app I'm testing. It works perfectly in my browser but when I test it on my phone through PhoneGap CLI it falls over entirely. I have it set up with Weinre but it doesn't show errors in the console like a browser does. Anyway. I've narrowed it down to the fact that a global empty object I define at the beginning of the js is being treated as undefined, so when I try to add to it the code simply refuses to start the loop. In the Chrome log is is correctly defined as an object and works perfectly.

Here is my code:

var holding_layers_info = {};

function my_function() {
    console.log(typeof holding_layers_info); // this logs undefined on PhoneGap App and object on Chrome log
    // my loop here, adding values to holding_layers_info, which doesn't run because of the undefined object above
}

I am entirely baffled by this, can't find anything similar online and have no idea where to start fixing it. Defining the empty object with var holding_layers_info = new Object(); or simply leaving it as var holding_layers_info; doesn't make any difference either, not that I thought it would.

An empty object defined within a function works as expected, but I need this to be global.

EDIT: Here is an abridged version of my index.html:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="format-detection" content="telephone=no" />
        <meta name="msapplication-tap-highlight" content="no" />
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width" />
        <!-- This is a wide open CSP declaration. To lock this down for production, see below. -->
        <!-- <meta http-equiv="Content-Security-Policy" content="default-src * 'unsafe-inline'; style-src 'self' 'unsafe-inline'; media-src *" /> -->
        <!-- Good default declaration:
        * gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication
        * https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly
        * Disables use of eval() and inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:
            * Enable inline JS: add 'unsafe-inline' to default-src
            * Enable eval(): add 'unsafe-eval' to default-src
            * Create your own at http://cspisawesome.com
        -->
        <!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: 'unsafe-inline' https://ssl.gstatic.com; style-src 'self' 'unsafe-inline'; media-src *" /> -->

        <link rel="stylesheet" type="text/css" href="css/ol.css">
        <link rel="stylesheet" type="text/css" href="css/index.css" />
        <link rel="stylesheet" type="text/css" href="css/fonts.css" />
        <link rel="stylesheet" type="text/css" href="css/easy-autocomplete.css" />
        <title>La la la</title>
    </head>
    <body>
        <!-- Boring HTML-only page content here -->

        <script src="https://code.jquery.com/jquery-1.12.4.min.js"
            integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="
            crossorigin="anonymous"></script>
        <script type="text/javascript" src="js/ol.js"></script>
        <script type="text/javascript" src="js/general.js"></script>
        <script type="text/javascript" src="js/jquery.easy-autocomplete.min.js"></script>
        <script type="text/javascript" src="js/index.js"></script>
        <script type="text/javascript">
            app.initialize();
        </script>
    </body>
</html>
Helen Danger Burns
  • 421
  • 2
  • 9
  • 28
  • "I define at the beginning" - Are you sure you're not just getting a bad result because of some underlaying problem? Like, for example, did you make sure you included the cordova.js and let the app initialize before you start running functions and such? – NoobishPro Sep 09 '16 at 23:12
  • @Babydead yep. The function is called from on Device Ready and cordova.js is included. I should add that I've been developing this app for a while now and is all been fine but this has just come out of nowhere... and why the difference between chrome and device? – Helen Danger Burns Sep 09 '16 at 23:17
  • Uhm... I don't know. I'm building 2 phonegap apps myself right now and I too have had issues, which were also accepted in chrome but not in the final build. I have had many issues however, with doing what you're doing. `var variable = {};`. This was definitely giving me errors, even on chrome. Hold on, I'm just going to put my debug into an answer so you can actually get the error and we can figure out a next step! – NoobishPro Sep 09 '16 at 23:24

1 Answers1

1

On the very first JS script I load, I make sure I have this function on top for debugging purposes:

//debugging
var debug = true;
if (debug) {
  window.onerror = function (msg, url, linenumber) {
    alert('Error message: ' + msg + '\nURL: ' + url + '\nLine Number: ' + linenumber);
    return true;
  };
}

This basically alerts every error that would usually come from the console. If this gives you an error, I think it would be very helpful!

With the information we have now, I'm quite sure nobody can actually answer your question. It's just too vague. Come back to me =)


I'm just going to throw this out there, because you never know: Did you maybe forget to remove the onDeviceReady functionality from the index.js that comes with the template of Phonegap?

Talking about this part:

onDeviceReady: function() {
    app.receivedEvent('deviceready');  //You should place YOUR starting function here!
},    
receivedEvent: function(id) {
  var parentElement = document.getElementById(id);
  app.receivedEvent('deviceready');
  var receivedElement = parentElement.querySelector('.received');//Quite sure you removed this element from the DOM :)

  listeningElement.setAttribute('style', 'display:none;');
  receivedElement.setAttribute('style', 'display:block;');

  console.log('Received Event: ' + id);
}

You see, this part is selecting DOM elements which you have probably removed. I have noticed on my projects that chrome doesn't kill off your JS anymore when you trigger something on non-existing elements.

Calling your own (Starting) function from there, would go somewhat like this:

onDeviceReady: function() {
   MyInitFunction();
}

-- you can remove the rest. (the entire receivedEvent: function)

On a small sidenote, I now see you are using jQuery 1.x. Since you're creating a mobile app, you really don't have to worry about backwards compatibility for older browsers. I'm currently using 2.x, but I think there would be no harm into switching to the new (much faster) 3.x

NoobishPro
  • 2,539
  • 1
  • 12
  • 23
  • Oh my word this debug function in itself is brilliant! Thank you! Just adding it now and we shall see. Thanks again. – Helen Danger Burns Sep 09 '16 at 23:32
  • I get this: `Error message: TypeError: null is not an object (evaluating 'parentElement.querySelector')` referencing the line where I define the global empty object. – Helen Danger Burns Sep 09 '16 at 23:38
  • OH! Could you pretty please post your index.html? More importantly to me; the positions of where exactly you include which JS files? -- I think I know what the problem is. – NoobishPro Sep 09 '16 at 23:52
  • I updated my answer with the probable cause. I'm like, 80% sure this is the problem, and not your variable ;) – NoobishPro Sep 09 '16 at 23:57
  • I've added the index.html – Helen Danger Burns Sep 10 '16 at 00:07
  • Oooo, you addition is interesting... index.js is still exactly as I found it... which bits do I need to remove? And is it ok to call my starting function like this `document.addEventListener("deviceready", onDeviceReady, false);` right at the top of the page (referencing a function onDeviceReady further down the page)? – Helen Danger Burns Sep 10 '16 at 00:10
  • I added comments to my example. The `app.receivedEvent('deviceReady');` is calling to the function below it (`receivedEvent: function(id)`) you can delete both of those entirely. (Don't forge to delete the "," at the end). Now, IF you want to trigger a function from this event, you can trigger any named function you want. Just like you would any other. for example: `init();`. (which is what mine is called.). Just replace `app.receivedEvent('deviceready');` with `init();` Let me update my answer with a proper example – NoobishPro Sep 10 '16 at 00:13
  • Good point on JQuery. Will do. I commented out the entire recievedEvent block and edited the onDeviceReady one to cal my function (which is in general.js) but that broke it. So I commented out both blocks and am back to using `document.addEventListener("deviceready", onDeviceReady, false);`which is fine by me. The initial error is gone but it's still ready the empty object as undefined and errors when the loop tries to start. Any ideas? – Helen Danger Burns Sep 10 '16 at 00:43
  • oh dear, yes, you needed to keep that eventlistener! By remove all I simply meant to remove all the rest that I had in my example! ahahaha. Could you move to chat with me? It'd make things easier, I'm sure. – NoobishPro Sep 10 '16 at 00:58
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/123028/discussion-between-babydead-and-helen-danger-burns). – NoobishPro Sep 10 '16 at 00:58
  • Guess you couldn't join the chat. I should go to bed soon... As for the undefined object... Make sure it's not undefined? I have no idea how you set it and when you trigger it. Are you sure which object you're speaking of? – NoobishPro Sep 10 '16 at 01:17