Ben Nadel: Monkey-Patching The $q Service With .fcall() & $decorator In AngularJS

fcall() promises using $decorator

by nickadeemus2002

HTML

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
<div ng-app="Demo" ng-controller="AppController">
    
<h1>Monkey-Patching The $q Service With .fcall() and $decorator In AngularJS</h1>

    <p><em><storng>Note</strong>: This is not exactly the .fcall() method from Q. Rather, this is inspired by that concept.</em>

    </p>
</div>

CSS

a[ng-click] {
    cursor: pointer;
    text-decoration: underline;
}
p.apply, p.digest {
    background-color: #FAFAFA;
    border: 3px solid #CCCCCC;
    cursor: default;
    float: left;
    height: 75px;
    line-height: 75px;
    text-align: center;
    width: 200px;
}
p.apply {
    margin-right: 30px;
}
p.apply.hot, p.digest.hot {
    background-color: #FFCCCC;
    border-color: #FF3399;
}
p.logging {
    clear: both;
}

JavaScript

// Create an application module for our demo.
var app = angular.module("Demo", []);

// I monkey-patch the .fcall() method into the root of the $q service. We have
// to do this in a .config() block so that we have an opportunity to decorate /
// augment the service before anything else in the application needs access to
// it. The config blocks will run before the .run() blocks ... run.
app.config(

function monkeyPatchQService($provide) {

    // Register a decorator for the $q service.
    // --
    // NOTE: Defining decorator below in order to reduce indentation.
    $provide.decorator("$q", decorateQService);


    // Our decorator will get called when / if the $q service needs to be
    // instantiated in the application. It is made available as the
    // "$delegate" reference (made available as an override in the "locals"
    // used to .invoke() the method. Other services can be injected by name.
    // --
    // NOTE: This decorator MUST RETURN the "$q" service, otherwise, $q will
    // be undefined within the application.
    function decorateQService($delegate, $exceptionHandler) {

        // Create a "natural" reference to our delegate for use locally.
        var $q = $delegate;
        // Monkey-patch our fcall() method.
        $q.fcall = fcall;

        // Return the original delegate as our instance of $q.
        return ($q);


        // ---
        // PUBLIC METHODS.
        // ---


        // I invoke the given function using the given arguments. If the
        // invocation is successful, it will result in a resolved promise;
        // if it throws an error, it will result in a rejected promise,
        // passing the error object through as the "reason."
        // --
        // The possible method signatures:
        // --
        // .fcall( methodReference )
        // .fcall( methodReference, argsArray )
        // .fcall( context, methodReference, argsArray )
        // .fcall( context, methodName, argsArrray )
        // .fcall(...