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?
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?
Share Improve this question asked Feb 18, 2014 at 0:52 AdeAde 3,0414 gold badges33 silver badges49 bronze badges 9-
deviceready
event is used for using the cordova API – Jonathan de M. Commented Feb 18, 2014 at 1:03 -
Yes, it's
deviceready
from the Cordova API that the EventListener is listening for. – Ade Commented Feb 18, 2014 at 1:05 -
So why bootstraping angularJS when cordova is ready? Angular do not need cordova API to be ready to run, you could call the
deviceready
after bootstraping angular. – Jonathan de M. Commented Feb 18, 2014 at 1:06 -
I don't know why, but bumping it down the event loop with a
setTimeout(init,0)
might work.. – calebboyd Commented Feb 18, 2014 at 3:13 - 1 you should listen for device ready in your outermost angularjs controller, after bootstraping ng – Jonathan de M. Commented Feb 18, 2014 at 16:24
3 Answers
Reset to default 5The 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
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.
- According to the Cordova deviceready docs, you are supposed to attach to the deviceready event in the onLoad event
- 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.