8

I want some understanding on two programming patterns I've seen and when to employ them. The question is about callbacks and delegate.

In the first code there are two distinct functions, success and fail, something I've always used, but the second code is different.

 function loadWebs() {

       var clientContext = new SP.ClientContext.get_current();

       this.webs = clientContext.get_web().get_webs();

       clientContext.load(this.webs);

       clientContext.executeQueryAsync(Function.createDelegate(this, this.onWebsLoaded), Function.createDelegate(this, this.onQueryFailed));

    }

    function onQueryFailed(sender, args) {

       alert('request failed ' + args.get_message() + '\n' + args.get_stackTrace());

    }

    function onWebsLoaded(sender, args) {

       for (var i = 0; i < this.webs.get_count(); i++) {

       alert(this.webs.itemAt(i).get_title());

       }    
    }

and the second code doesn't appear to use callbacks for the success, instead the success is wrapped in the parent function.

  myCtx.load(webs, "Include(Id, Lists)");

    myCtx.executeQueryAsync(function () {
        // push new SP.ListItemCollections into an array and tell the ctx to fetch them
        for (var i = 0; i < webs.get_data().length; i++) {
            var web = webs.get_data()[i], itms;  
     if (checkForProjectsList(web)) {
                itms = webs.get_data()[i].get_lists()
                           .getByTitle("Projects").getItems(query);
                queryItemCollections.push(itms);
                myCtx.load(itms);
            }



        }


    myCtx.executeQueryAsync(function () {
            queryItemCollections.forEach(function (item) {
                // do work with individual list items here
                console.log(item.getItemAtIndex(0).get_item("Title"));
            });
        }, genericFailHandler);
    }, genericFailHandler);


function genericFailHandler(sender, args) {
        console.log(args.get_message());
    }

Thanks

1 Answer 1

9

states:

SP.ClientContext.executeQueryAsync( succeededCallback , failedCallback )

So in both your examples you are referencing a function (callback) as parameter.
The only difference being the declaration of the function.

With

clientContext.executeQueryAsync(
    function () {
        queryItemCollections.forEach(function (item) {
            console.log(item.getItemAtIndex(0).get_item("Title"));
        });
    }
  , genericFailHandler
);

you create a (anonymous) Success function callback (expression) which can not be (re)used by any other code.

While with:

clientContext.executeQueryAsync(
  Function.createDelegate(this, this.onWebsLoaded),
  Function.createDelegate(this, this.onQueryFailed)
);

you have declared seperate functions, so you could use that function (declaration) for other calls as well.

Function.createDelegate

Is (old, never a official standard) JavaScript code to bind the outer function this context to your function, it is supported in all browsers.
.bind(this) is standard ES5 JavaScript code
IE9 was the first IE version to support this .bind() notation. You need a Polyfill to support older IE browsers

So

clientContext.executeQueryAsync(
  this.onWebsLoaded.bind(this),
  this.onQueryFailed.bind(this)
);

is a more modern notation

But in your examples above you do nothing with the this context inside the Fail function.

So you might as well write:

clientContext.executeQueryAsync(
  this.onWebsLoaded.bind(this),
  this.onQueryFailed
);

And since your first example declares those functions as Global functions, you can write:

clientContext.executeQueryAsync(
  onWebsLoaded.bind(this),
  onQueryFailed
);

Learning this

Is a cool blog which also lets you play with this in JSBins


Great explanation (including modern Arrow Functions):

http://2ality.com/2017/12/alternate-this.html


J1 J5 JSOM JX iBind

4
  • In the second example there are two calls to myCtx.executeQueryAsync. The first appears to get Projects lists and the second one gets every Title of the 1st Item in the Project list. The 1st call builds myCtx.load(itms) and this gets executed in the second call. Is this correct? Commented Dec 15, 2015 at 15:32
  • Yes there are nested callbacks,That code is much better to read when restuctured to use declared functions. Commented Dec 15, 2015 at 15:44
  • So the use of bind won't work on IE 8? What about SP sites where the site defaults to IE8 compatibility mode on IE 11? Commented Oct 19, 2016 at 12:36
  • You can test with Function.call.bind({}); in the F12 console Commented Oct 19, 2016 at 13:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.