Best practices to be sure that cordova plugins are loaded, platform.ready

Hi

I saw several threads on the forum where people say that the cordova plugins must be initialized in $ionicPlatform.ready(function() {....
But I don’t really understand how to do this.

For instance, I have

in the .run:

.run(         ['$rootScope', '$window', '$state', '$translate', 'sAuth', "isPhoneGap","connectionStatus", 'updateProDB', "$ionicPlatform", '$q', 'storageService', 'imagesService', 'usersDatabase', function($rootScope ,  $window ,  $state ,  $translate ,  sAuth ,  isPhoneGap , connectionStatus ,  updateProDB , $ionicPlatform ,  $q ,  storageService ,  imagesService) {
  
   $ionicPlatform.ready(function() {
    ...
    var promiseUpdateProDB = updateProDB.get();
    promiseUpdateProDB.then(
          function(prodata) {
              var prodata = storageService.get('prodata');
              imagesService.manageStoredImageUrlsNew(prodata);

              $rootScope.imagesUrlsAreStored.resolve();
          },
          function(error) {});
     ...
    }
 }]);

and the service updateProDB uses another service called connectionStatus where I need the cordova-network-information-plugin:

.service('updateProDB', ['isPhoneGap', 'connectionStatus', 'isIOS', '$q', 'storageService', 'sendToServer', function updateProDBFactory(isPhoneGap, connectionStatus, isIOS, $q, storageService, sendToServer) {
...

and

factory('connectionStatus', ['isPhoneGap', function connectionStatusFactory(isPhoneGap) {
....

So is that code ok ?
I am testing it right now in ios simulator, and the app is stuck on a white screen, with this error in the console: TypeError: undefined is not an object (evaluating 'navigator.connection.type) which means that the plugin is not loaded.

Should I put $ionicPlatform.ready(function() { within the service code ?

It’s like code within the service is run before I even use the service itself. I don’t understand.

Can you help clarify the best practices ?

Thanks

EDIT ouch, I just change my connectionStatus .factory into a .service, and now it works… I can’t wrap my head around this factory/service thing… I don’t see, even if a factory is just a “method” and is not instiated, why would it be executed before I call it, as it seems to be the case here.

You are correct that if you want to initialize somethings once the app loads, they should go in the $ionicPlatform.ready function of your .run function.

If you have any functions that execute immediately within the service/factory, what is happening is those are fired once you inject the service/factory, without even calling any methods. And that could be causing the error.

So I have a few recommendations for you. First I’ll touch on how to fix that, then I’ll mention something you could change about your .run function to make it “more readable” and follow best practices, then I’ll touch on something to make all your services more readable. It’ll be a lot to read, but you seem like someone who is eager to learn and would take advantage of some “code feedback” :wink:

  1. How to stop it from firing once the factory is injected:
    -> Create an init function in the factory, that does all of the logic you need when the app loads. Like check the connection status in your case. And make sure you return that init function so you can access it outside your factory. I would write it like this inside your factory:

    var init = function(){
    // Do your connection magic here
    }

    // more factory code
    var otherFactoryMethod = function(){
    // do cool stuff
    }

    // Bottom of factory. You are essentially exposing these
    // so you can use them elsewhere
    return {
    init : init,
    otherFactoryMethod : otherFactoryMethod
    }

Then in your .run function, you can prevent your factory from initializing once it is injected. Now, you can just call myFactory.init() once the ionicPlatform is ready. Make sense?

  1. How to “improve” your .run function
    -> So right now, it looks like you have a lot of logic going on in your .run function, which is fine, it works, but you aren’t really following separation of concerns. You mentioned best practices, and in my experience, this is very, VERY important.

Basically with separation of concerns, each service/factory/controller/directive/filter is in charge of one thing. Not just one method, but handling one part of the app, if that makes sense. So I have a user service which is meant for just handling user logic like changing their name. Then I have a profile service which is used for just handling saving things for their profile. I also have an AuthService for signups/password resets/logins/logouts.

Now, with everything separated and “isolated” if something isn’t working for signups, I know exactly where to look and whats going on. If I need to add a method for the user to change the avatar, I know exactly what service will handle that. It makes maintaining your code immensely easier.

I leave all app initializing to app.js .run function. You are sort of doing that now, but you also have some logic in there that looks like it belongs in your updateProDB service instead. Try and keep app.js more barebones and just call the init functions you need.

  1. Last point. To make the code a little more readable, I try and keep the code line width a lot shorter, so I don’t have to scroll to see what is injected in this service.

So you have

.run(['$rootScope', '$window', '$state', '$translate', 'sAuth', "isPhoneGap","connectionStatus", 'updateProDB', "$ionicPlatform", '$q', 'storageService', 'imagesService', 'usersDatabase', function($rootScope ,  $window ,  $state ,  $translate , sAuth ,  isPhoneGap , connectionStatus ,  updateProDB , $ionicPlatform ,  $q ,  storageService ,  imagesService)

And I would change it to look like:

.run(['$rootScope', '$window', '$state', 
       '$translate', 'sAuth', "isPhoneGap",
       "connectionStatus", 'updateProDB', "$ionicPlatform", '$q', 
       'storageService', 'imagesService', 'usersDatabase', 
       function($rootScope ,  $window ,  $state ,  
                    $translate , sAuth ,  isPhoneGap ,
                     connectionStatus ,  updateProDB , $ionicPlatform ,  
                    $q ,  storageService ,  imagesService`){
       
       }
    ]);

See how you can now see exactly what you are injecting without having to scroll through it all? Yes, it adds more lines to your code, but in exchange it is more readable.

Finally, you mentioned you just can’t wrap your head around factory/services, and I just want to say, it is a hard concept to grasp, so don’t beat yourself up and think you’ll never get it. I’ve been developing Angular apps for quite some times now, and I still make mistakes and misuse it. Its not the end of the world, you learn, and by using them more and more, and getting feedback, like you are doing now, eventually it’ll become second nature.

If you want to read up on them, here is a good stack overflow post that I constantly go back to refresh myself about the differences:

So that was a lot haha. Just love helping people build epic shit :wink: Good luck and let me know if you need help

Cheers.

3 Likes

Whoa ! super nice, I will for sure take advantage of such great code feedback.
I am going to read the stackoverflow post right now, an rearrange my code to comply with the best practices you mentionned.

Thanks a lot @DaDanny !!