Skip to content
This repository has been archived by the owner. It is now read-only.

Using $ionicPlatform.ready() in module.js before plugins are initialized #8

Open
pbernasconi opened this issue Jun 2, 2014 · 32 comments

Comments

@pbernasconi
Copy link
Contributor

pbernasconi commented Jun 2, 2014

What do you think about returning a promise in the module which uses $ionicPlatform.ready() to make sure the plugins are not used until the dom is ready?

angular.module('ngCordova', [ngCordova.plugins])
  .factory('ngCordova', function ($q, $rootScope, $ionicPlatform) {
    var deferred = $q.defer();

    $ionicPlatform.ready(function () {
      console.log('ionic is ready');
      $rootScope.$apply(deferred.resolve);
    });

    return {
      ready: function () {
        return deferred.promise;
      }
    };
  })
  .run(function (ngCordova) {});

Then each plugin uses the ngCordova service service like so:

.factory('Notification', function ($q, ngCordova) {
  return {
    alert: function (message, alertCallback, title, buttonName) {              
       ngCordova.ready().then(function () {
          navigator.notification.alert(message, alertCallback, title, buttonName);
       });
    }
  };
});
@rtpm
Copy link

rtpm commented Jun 4, 2014

This is a must imho, but I would use a "deviceready" event instead of $ionicPlatform.ready().

@krik
Copy link

krik commented Jun 4, 2014

Yeah, "deviceready" would be cool!

@sidneys
Copy link
Contributor

sidneys commented Jun 4, 2014

+1

@EnchanterIO
Copy link

EnchanterIO commented Jun 6, 2014

Ah I killed last two hours trying to figure out why this isn't working... then I tried to wrap it all with timeout for 5s and wuala...

Until your suggestion will be in the official cordova api what do you guys think is the cleanest way to solve my situation please ?

LandingPage
 .controller('landingPageCtrl', ['$scope','$cordovaDevice','$timeout',
     function($scope, $cordovaDevice, $timeout) {
         $scope.onlineOrNot = {
             text: 'not'
         };

        $timeout(function() {
            var device = $cordovaDevice.getDevice();
            var cordova = $cordovaDevice.getCordova();
            var model = $cordovaDevice.getModel();
            var platform = $cordovaDevice.getPlatform();
            var uuid = $cordovaDevice.getUUID();
            var version = $cordovaDevice.getVersion();

            $scope.onlineOrNot.text = version;

        },5000);

        $scope.onlineOrNot.text = "not breaking anymore";

    }
])

@quanghoc
Copy link

quanghoc commented Jun 9, 2014

I believe the ionic.js already had deviceready embeded in $ionicPlatform.ready so getting a separate deviceready would be redundant.

  function onWindowLoad() {
    if(ionic.Platform.isWebView()) {
      // the window and scripts are fully loaded, and a cordova/phonegap
      // object exists then let's listen for the deviceready
      document.addEventListener("deviceready", onPlatformReady, false);
    } else {
      // the window and scripts are fully loaded, but the window object doesn't have the
      // cordova/phonegap object, so its just a browser, not a webview wrapped w/ cordova
      onPlatformReady();
    }
    window.removeEventListener("load", onWindowLoad, false);
  }

The problem is services and controllers module would load before the $ionicPlatform.ready being called in app.js. So I would not suggest implementing ngCordova.ready() per plugin as @pbernasconi mentioned. That would have some overhead (although tiny). I would use ionic.Platform in http://ionicframework.com/docs/angularjs/utils/platform/ or $ionicPlatform like below:

controller('MyCtrl', function($scope, $ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Your code
    $scope.$digest();
  });
});

Make sure to put the $scope.$digest(); at the end if you want to update angular rendering engine.

I am wondering if there is a better way to detect ionicPlatform ready even before loading angular modules for Cordova only.

@mlynch
Copy link
Member

mlynch commented Jun 9, 2014

We should add a separate, non ionic-prefixed thing here. It's okay if they overlap since they will both fire correctly.

Maybe something like $cordova which has some functions like

$cordova.ready(function() {
});

@quanghoc
Copy link

quanghoc commented Jun 9, 2014

Yeah something as an overall "umbrella" prior to loading angular modules would work. So that there is no ready() check here and there in the controllers. It's necessary to load everything upfront anyways.

@romgar
Copy link
Contributor

romgar commented Jul 11, 2014

An another way is to initialize angular dynamically when cordova is ready.

window.ionic.Platform.ready(function() {
    angular.bootstrap(document, ['<your_main_app']);
});

Works like a charm.

@okonon
Copy link

okonon commented Jul 11, 2014

Hey @Natsu- how does this behave when developing in a browser? Cordova ready is not fired while in a browser. Does it still bootstraps the app?

@romgar
Copy link
Contributor

romgar commented Jul 11, 2014

Yes, app is also bootstrapped in a browser.
Look at ionic.Platform.ready() description (from ionic code source) :

    /**
     * @ngdoc method
     * @name ionic.Platform#ready
     * @description
     * Trigger a callback once the device is ready, or immediately
     * if the device is already ready. This method can be run from
     * anywhere and does not need to be wrapped by any additonal methods.
     * When the app is within a WebView (Cordova), it'll fire
     * the callback once the device is ready. If the app is within
     * a web browser, it'll fire the callback after `window.load`.
     * @param {function} callback The function to call.
     */

@nicowenterodt
Copy link

nicowenterodt commented Aug 6, 2014

Hi @Natsu- , I tested your approach. Works good in browsers. But on iOS it fails - ending up with a white screen.

I removed the ng-app directive from the body tag and bootstrapped it like you said within the Platform.ready ..

@romgar
Copy link
Contributor

romgar commented Aug 6, 2014

Do you have some error logs ? On XCode / Safari web inspector ?

@nicowenterodt
Copy link

nicowenterodt commented Aug 6, 2014

There were no errors shown within the console. But now I wrapped that into a try- block and catched the exception with an alert so I found out that the error was the following:

undefined is not an object window.cordova.plugins.Keyboard
ionic.Platform.ready(function(){
  try{
    angular.bootstrap(document.body, ['my_app']);     
  }
  catch(e){
    alert(e)
  }
})

in app.js

.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
  });
})

As soon as I removd the Keyboard-Plugin lines it starts working.. so I double checked the installed plugins and found out that for any reason I don't now the keyboard plugin was not configured anymore in the ios.json

Afer reinstalling the Plugin it now works.

cordova plugin add https://github.com/driftyco/ionic-plugins-keyboard.git

Thanks @Natsu- for your approach. Works perfectly for me now.

@romgar
Copy link
Contributor

romgar commented Aug 7, 2014

Well done !

@pbernasconi pbernasconi modified the milestone: v0.2.0-beta Sep 3, 2014
@emertechie
Copy link

emertechie commented Sep 14, 2014

I was able to use the resolve feature of the UI router to wait for ionic.Platform.ready signal before each state that might need a plugin:

$stateProvider
    .state('screen', {
        url: '/screen',
        abstract: true,
        templateUrl: 'templates/layout.html',
        resolve: {
            cordova: function($q) {
                var deferred = $q.defer();
                ionic.Platform.ready(function() {
                    console.log('ionic.Platform.ready');
                    deferred.resolve();
                });
                return deferred.promise;
            }
        }
    })

@quanghoc
Copy link

quanghoc commented Sep 14, 2014

Then you still have to check for the cordova variable inside the controller. It's not different from using ionic.Platform.ready directly.

@emertechie
Copy link

emertechie commented Sep 15, 2014

@quanghoc Perhaps I'm missing something but the promise returned from the resolve.cordova fully resolves before my controller is called (even if I don't declare a cordova parameter) so I don't have to wait on anything in the controller. This way, I only need one call to ionic.Platform.ready in an abstract state and not repeated in multiple controllers.

@quanghoc
Copy link

quanghoc commented Sep 15, 2014

Oh I think you're right.

We must state to the users this solution require the use of ui-router

@simoneb
Copy link

simoneb commented Oct 12, 2014

@natsu perfect approach!

@pbernasconi
Copy link
Contributor Author

pbernasconi commented Oct 19, 2014

A new WIP is happening @ #386. Would love to hear your thoughts and comments

krizroring added a commit to krizroring/ng-cordova that referenced this issue Dec 21, 2014
Changed the install link back to the original author, after acceptance of pul request ionic-team#8 on the master branch of phonegap-plugin-brightness.
@JerryBels
Copy link

JerryBels commented Jan 3, 2015

Any news about this ? Adding the "ready" condition to the plugins ?

@matiasurbano
Copy link
Contributor

matiasurbano commented Feb 13, 2015

Same as @JerryBels, there is any news about it?

@ms88privat
Copy link

ms88privat commented Apr 25, 2015

+1 ?

@simpixelated
Copy link

simpixelated commented Jul 23, 2015

@pbernasconi blogged about adding this on the Ionic blog back in December 2014, but it's still hasn't been added. Would love to hear some news.

@ghost
Copy link

ghost commented Jul 23, 2015

+1 to what @simpixelated said

@mbarzeev
Copy link

mbarzeev commented Jul 27, 2015

+1 for @emertechie abstract view suggestion

@Stajor
Copy link

Stajor commented Sep 30, 2015

+1

@ghost
Copy link

ghost commented Sep 30, 2015

Here's a nice work around I found for this recently:
http://stealthcode.co/multiple-calls-to-ionicplatform-ready/

@sgentile
Copy link

sgentile commented Oct 13, 2015

I've wasted hours here, why would all the examples show ,

ie.  if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
                cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
                cordova.plugins.Keyboard.disableScroll(true);

            } 

If none of the plugins are loaded on $ionicPlatform.ready ? when my app starts I need to register notifications, I do this on run and use $ionicPlatform.ready - but I'm seeing the behavior where where window.cordova isn't defined

@bitflower
Copy link

bitflower commented Nov 11, 2015

I used @romgar's solution posted here. #8 (comment)

@eduardo-marcolino
Copy link

eduardo-marcolino commented Jul 27, 2017

@emertechie thanks for the code!
It worked using $routeProvider too:

    $routeProvider
        .when('/', {
            templateUrl: 'views/home.html',
            controller: 'homeController',
            resolve: {
              cordova: function($q) {
                 var deferred = $q.defer();
                 document.addEventListener("deviceready", function () {
                   console.log('ionic.Platform.ready');
                   deferred.resolve();
                 });
                 return deferred.promise;
              }
            }
        })

@julitroalves
Copy link

julitroalves commented Aug 17, 2017

Thanks @romgar, it works for me too.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests