Search code examples
javascriptajaxes6-promise

Custom ajax promise function signature


I want to basically create a new function signature for ajax done and fail handlers...given the simplified example below, I'm just trying to append resource as the last parameter to be sent to the handler.

    const customAjax = function( url, resource ) {
        const p = $.ajax({
            converters: {
                'text script': function (text: string) {
                    return text;
                }
            },
            url: url + "?" + resource
        }).then(
            function () {
                [].push.apply(arguments, [resource]);
                return arguments;
            },
            function() {
                [].push.apply(arguments, [resource]);
                return arguments;
            }
        );

        return p;
    };

Then the preferred usage is something like:

customAjax( "url", "resourceKey" )
   .done( function( data, textStatus, jqXHR, resourceName ) { /* do something */ } )
   .fail( function( jqXHR, textStatus, errorThrown, resourceName ) { /* do something */ } );

The problem is, in both handlers, there is only one parameter. The javascript arguments object. So, to access each parameter I really want, I have to do something like this instead:

customAjax( "url", "resourceKey" )
   .done( function( args ) { 
      var data = args[ 0 ];
      var textStatus = args[ 1 ];
      var jqXHR = args[ 2 ];
      var resourceName = args[ 3 ];
      /* do something */
   } )
   .fail( function( args ) { 
      var jqXHR = args[ 0 ];
      var textStatus = args[ 1 ];
      var errorThrown = args[ 2 ];
      var resourceName = args[ 3 ];
      /* do something */ 
} );

Is there any way to make it work the way I'd prefer?

Update - Not sure how to communicate with person that closed my question, but I don't see how the referenced 'duplicate' question answers/addresses my issue.


Solution

  • You would need to overwrite the fail and done method properties of the object that $.ajax returns, so to make sure that the callback that is eventually passed to these two methods is then called with the extra argument:

    const customAjax = function( url, resource ) {
        const p = $.ajax({
            converters: {
                'text script': function (text: string) {
                    return text;
                }
            },
            url: url + "?" + resource
        });
        let result = {
            ...p,
            done(f) {
                p.done(function (...args) {
                    f.call(this, ...args, resource);
                });
                return result;
            },
            fail(f) {
                p.fail(function (...args) {
                    f.call(this, ...args, resource);
                });
                return result;
            }
        };
        return result;
    };
    

    Demo:

    const customAjax = function( url, resource ) {
        const p = $.ajax({
            converters: {
                'text script': function (text) {
                    return text;
                }
            },
            url: url + "?" + resource
        });
        let result = {
            ...p,
            done(f) {
                p.done(function (...args) {
                    f.call(this, ...args, resource);
                });
                return result;
            },
            fail(f) {
                p.fail(function (...args) {
                    f.call(this, ...args, resource);
                });
                return result;
            }
        };
        return result;
    };
    
    
    customAjax( "https://jsonplaceholder.typicode.com/todos/1", "resourceKey" )
        .done( function( data, textStatus, jqXHR, resourceName ) { 
            console.log( {data, textStatus, jqXHR, resourceName});
        });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>