Search code examples
javascriptangularjsdependency-injectioncordova-3

Angular.js dependency injection in global function


I am writing a cordova application with angular.js. When I use the PushPlugin to send push notifications to the user. I have register the user phone like this:

var pushNotification = window.plugins.pushNotification;
    pushNotification.register(successHandler, errorHandler, { "senderID": [gmc_project_number], "ecb": "app.onNotificationGCM" });

The last parameter that I pass is app.onNotificationGCM this is a function that is called when I receive a notification.

This is the implementation of that function:

 app.onNotificationGCM = function (e) {
    switch (e.event) {
        case 'registered':
            if (e.regid.length > 0) {
                console.log("Regid " + e.regid);
                alert('registration id = ' + e.regid);
            }
            break;

        case 'message':
            // this is the actual push notification. its format depends on the data model from the push server
            alert('message = ' + e.message + ' msgcnt = ' + e.msgcnt);
            break;

        case 'error':
            alert('GCM error = ' + e.msg);
            break;

        default:
            alert('An unknown GCM event has occurred');
            break;
    }
};

I have to add it in a global variable (in this case the angular.module), in order for it to be accessible when the response is returned.

This is the explanation that I got from https://github.com/phonegap-build/PushPlugin/issues/309

Because the Android JAVA code calls a function (I saw it in the LogCat) called sendJavascript() this function contain a string that contain the function onNotificationGCM(Json) that is called in the document so if you load the function in the "onDeviceReady" it will be avalaible only when the device is ready and not always like is supposed to be (the registrration takes a few seconds to come back)

As it is now it works just fine. The problem is that I want to call a factory and make an http call from it inside onNotificationGCM. Currently I don't know how to inject the factory. I tried assigning the onNotificationGCM function to $rootScope but it was not accessible on the response.

Is there a way to inject a factory inside this global function? Is there another way to implement this, perhaps inside app.config()?


Solution

  • If you have an Angular $injector (ref) for your application, you can easily call a function with dependency injection:

    $injector.invoke(["$http", myfunction]);
    

    You could, for instance, wrap the entire function as:

    app.onNotificationGCM = function (e) {
        $injector.invoke(["$http", function($http) {
            // your code here... it will be dependency injected by Angular
        }]);
    };
    

    You will most definitely want to call $apply() - $http calls will not run before, so actually the code should be:

    app.onNotificationGCM = function (e) {
        $injector.invoke(["$http", "$rootScope", function($http, $rootScope) {
            $rootScope.$apply(function() {
                // your code here... it will be dependency injected by Angular
                // ... AND called properly in a digest cycle
            });
        }]);
    };
    

    That is only part one. Now the question is how do you get hold of the proper $injector for your application?

    If you bootstrap manually, then angular.bootstrap (ref) returns the injector. Just keep it in a (global?) var.

    You probably use ng-app. Then you will have to identify the element that contains ng-app somehow and call angular.element.injector (ref - look for "jQuery/jqLite Extras"). E.g., if ng-app is in the <body>:

    // in code OUTSIDE Angular
    var $injector = angular.element(document.body).injector();