Aug 27, 2007

javascript delegate callback

In c#, you can create a delegate like the code below.
            class Animal
            {
            public string Greeting = "Hello,";
            public void Greet(string message)
            {
            Console.WriteLine(this.Greeting + message);
            }

            }

            class Client
            {
            public SampleDelegate TestDelegate;
            public void Demo()
            {
            Animal a = new Animal();
            TestDelegate = new SampleDelegate(a.Greet);
            TestDelegate("Ainmal");
            }
            }
            
But in javascript , "this" is in the context of caller. In asp.net ajax library, there is a function to create a delegate.
            Function.createDelegate = function Function$createDelegate(instance, method)
            {
            /// 
            /// 
            /// 
            var e = Function._validateParams(arguments, [
            {name: "instance", mayBeNull: true},
            {name: "method", type: Function}
            ]);
            if (e) throw e;
            //it is not the same as return method.apply(instance, arguments);
            return function() {
            return method.apply(instance, arguments);
            }
            }
            
Please note that is return a function pointer, and the function call the method in the context of instance.
            function pageLoad() {
            // test is a property of the window object.
            this.test = "I'm a test string!";

            // Create a delegate that points to onButtonClick and pass the
            // window object as the first argument.
            var clickDelegate = Function.createDelegate(this, onButtonClick);

            // Handle the click event with the delegate.
            $addHandler($get('testButton'), 'click', clickDelegate);

            //if we call,   $addHandler($get('testButton'), 'click', onButtonClick);
            // the "this" inside of the method will reference to  button, and its
            //test value is null

            }

            function onButtonClick() {
            // Access the window object.
            alert(this.test);
            }
            
The Function.createDelegate method is useful because you don’t have to store in a global variable—or even in a DOM element—the context that you want to access in the event handler.
            $addHandlers(buttonElement, { click:onButtonClick,
            mouseover:onMouseOver }, this);
            //"this" is context inside of event
            
Callback function in asp.net ajax library is similar to delegate, but they solve a different problem. Delegate solve the problem of "this" context, so that it accept instance parameter, the "this" will refer to instance. "this" in Callback function is still in the context of caller. But Callback function accept a context parameter. Both concept is very useful in ajax, because it is all about reuse. The section of code can be reuse in different "conext"!
            Function.createCallback = function Function$createCallback(method, context) {
            /// 
            /// 
            /// 
            var e = Function._validateParams(arguments, [
            {name: "method", type: Function},
            {name: "context", mayBeNull: true}
            ]);
            if (e) throw e;



            return function() {
            var l = arguments.length;
            if (l > 0) {
            var args = [];
            for (var i = 0; i < l; i++) {
            args[i] = arguments[i];
            }
            args[l] = context;
            return method.apply(this, args);
            }
            return method.call(this, context);
            }
            }

            //example
            function pageLoad() {
            // The context object.
            var context = { date : new Date() };

            // Create a callback that points to onButtonClick and pass
            // the context object.
            var clickCallback =
            Function.createCallback(onButtonClick, context);

            // Attach a handler to the click event of the button.
            $addHandler($get('myButton'), 'click', clickCallback);
            }

            function onButtonClick(evt, context) {
            // Here we can access both the event object and
            // the context.
            var loadTime = context.date;
            var elapsed = new Date() - loadTime;
            alert(this);
            alert((elapsed / 1000) + ' seconds');
            }