简体   繁体   中英

Trigger Action from Push Notification

I have a cordova application that uses push notification (still using the old plugin :-().

The application uses ngRouter and the navigation is relatively basic - in that I mean that my main menu changes ngView but popups/modals are not part of the navigation and are either triggered by some bound controller property or through a call to a controller function (eg $scope.openMyModal ).

I am trying to be able to call such function on one of my controllers after I received push notification (and the controller is loaded).

I implemented some code using a timeout to broadcast an event which should be caught in the relevant controller and open the modal. Roughly the code is:

In app.js:

onNotification() {
   // some code for determining the type of notification
   // then
   setTimeout(function() {
       $rootScope.$broadcast("someEventCode");
   }, 10); // or 1000 in case of cold start
}

In MyController.js:

.controller('MyController', function($scope, $rootScope, $modal,...) {
    $scope.openMyModal = function() { // open modal using $model }

    $scope.on("someEventCode", function() {
        $scope.openMyModal();
    });
}

This kind of works but is not consistent/deterministic. For example, in slower devices it may broadcast before the controller is ready to respond to it.

I also tried to set some variable on root scope (in onNotification ) and in the controller create a function which is called from the markup (eg {{isNotificationReady()}} ) but this also doesn't work well.

Another approach was to use double notifications - set a flag in root scope when the notification arrives, wait for an event from the target controller (indicating it is loaded) and then, at $rootScope again, if flag is set, broadcast the "open dialog" event (and delete the flag). Following this approach, I am not sure how to trigger the "loaded" event so I use a function from the markup:

In MyController.js:

$scope.isLoaded = function() {
    $scope.$emit("myControllerLoaded");
}

In markup:

<div><!-- the content --></div>
{{isLoaded()}}

In app.js

$rootScope.$on("myControllerLoaded", function(event) {
    if ($rootScope.notification === "someEventCode") {
        $rootScope.$broadcast("openTheModel");
        delete $rootScope.notification;
    }
});

This seems like cumbersome and inefficient code. isLoaded() is called multiple times (not sure why) and it is kind of spaghetti code.

My question is - how should I implement something like that in a clear and efficient manner? Just a reminder, the app could be "cold started" or in the background and I need to know when it is "running" (or the controller is ready).

I've found a slightly more robust, timeout based implementation (still not exactly what I was hoping for).

The idea is to set a flag and send (broadcast) the signal after some time. Then resend the signal on interval until the flag is unset by the target controller:

In app.js

function broadcastSomeEvent() {
    $rootScope.$broadcast("someEventCode");
    if ($rootScope.eventFlag) {
        setTimeout(broadcastSomeEvent, 50);
    }
}


onNotification() {
   // some code for determining the type of notification, then
   $rootScope.eventFlag = true;
   setTimeout(broadcastSomeEvent, 10); // or 1000 in case of cold start
}

In MyController.js

$scope.$on('someEventCode', function() {
    delete $rootScope.eventFlag;  // delete flag so event is stopped
    $scope.openMyModal();
});

This is still an iff-y implementation to my taste. Even though it does work for both cold start and when the application is in the background I believe that it is not robust as it should.

Still, I wouldn't mark this solution as "the answer".

On the other hand, with no proper state routing, maybe there's not much more than can be done.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM