Question

I'm using Cordova 3.3.1-0.4.2 and Angular 1.2.13

I need to manually bootstrap Angular once I get the Cordova 'deviceready' event.

I'm testing on a Nexus 5 with cordova run android but am having exactly the same behaviour on an iPhone.

To simplify the problem this is JS running in the global document scope. Scripts are being loaded before the closing </body> tag.


This works:

angular.bootstrap(document.getElementById("app"), ["MyApp"]);

This doesn't work:

function init(){
  angular.bootstrap(document.getElementById("app"), ["MyApp"]);
}

document.addEventListener('deviceready', function () {
  init();
}, true);

However if I add alert("init") to the init method that shows it IS running. Also alert(angular) and alert(document.getElementById("app")) show that they exist.

I don't understand why, given that init() is being called, it doesn't work when called from the EventListener callback yet it does work if called directly.

Seems weird / unintuitive.

Anyone?

Was it helpful?

Solution

The best solution I've found is to bootstrap Angular as normal and then load Cordova as a module that returns a promise, which is resolved when the device is ready.

angular.module('fsCordova', [])
.service('CordovaService', ['$document', '$timeout', '$window',  '$q',
  function($document, $timeout, $window, $q) {

    var defer = $q.defer();

    this.ready = defer.promise;

    // Backup in the case that we did not received the event
    // This seemed to be necessary with some versions of Cordova
    // when testing via 'cordova serve' in a web browser
    // but when on-device the event is received correctly
    var timoutPromise = $timeout(function() {
      if ($window.cordova){
        defer.resolve($window.cordova);
      } else {
        defer.reject("Cordova failed to load");
      }     
    }, 1200);

    angular.element($document)[0].addEventListener('deviceready', function() {
      $timeout.cancel(timoutPromise);
      defer.resolve($window.cordova);
    });  
  }
]);

Usage:

angular.module('app', ['fsCordova']).

run(['$window', function($window){
  // init Fastclick
  FastClick.attach(angular.element($window.document.body)[0]);
}]).

controller('AppCtrl', ['$scope', 'CordovaService', 
  function($scope, CordovaService){

    $scope.ready = false;

    // when cordova is ready
    CordovaService.ready.then(
      function resolved(resp) {
         $scope.ready = true;  
      },
      function rejected(resp){
        throw new Error(resp);
      }
    );
  }
]);

I've shared this bootstrap project here on GitHub

OTHER TIPS

To those who actually want to manually boostrap angularjs after cordova deviceready event should use this. you can also read details of it here AngularJS + Cordova (Updated And Even Better!)

'use strict';

var CordovaInit = function() {

var onDeviceReady = function() {
    receivedEvent('deviceready');
};

var receivedEvent = function(event) {
    console.log('Start event received, bootstrapping application setup.');
    angular.bootstrap($('body'), ['c3aApp']); // Manually add and boot Angularjs 
};

this.bindEvents = function() {
    document.addEventListener('deviceready', onDeviceReady, false);
};

//If cordova is present, wait for it to initialize, otherwise just try to
//bootstrap the application.
if (window.cordova !== undefined) {
    console.log('Cordova found, wating for device.');
    this.bindEvents();
} else {
    console.log('Cordova not found, booting application');
    receivedEvent('manual')
}
};

$(function() {
console.log('Bootstrapping!');
new CordovaInit();
});

I personally chose this method because I needed to get some data from SQlite db on the device for Angularjs configuration before Angularjs loads, and loading Angularjs first seems to break my code.

I have been using this method for sometime now and everything works well.

// PLEASE DO CHECK THE ORDER OF YOUR .js FILES.

  1. According to the Cordova deviceready docs, you are supposed to attach to the deviceready event in the onLoad event
  2. You maybe hitting a javascript library ordering problem

I posted the outline of a solution I came up with that does not require deferred initialization via promises and has been tested to work reliability on multiple emulators and physical iOS and Android devices on my blog.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top