Table of Contents
This chapter explains the use of delegates, which are a part of the mechanism that different parts of an OpenLaszlo application use to communicate with each other when values of attributes change.
You generally only need to be aware of delegates for objects that you create in script (that is, not with tags). For objects that you create with tags, for example <view>, you can manage communication using event handlers, as described in Chapter 29, Methods, Events, Handlers, and Attributes. When you use handlers, the OpenLaszlo runtime takes care of delegates for you. Delegates are still there, behind the scenes, but the system manages them invisibly. However, it's helpful to understand the relationship between tag and script-based event syntax.
The last section of this chapter explains how delegates compare to similar things in other programming languages.
The purpose of a delegate is to bind an event at runtime to a particular method. Thus to "register an event with a delegate" simply means to bind that event, temporarily, to the method that is invoked by the delegate. The event stays bound to that method until you "unregister" the delegate. This means, then, that when the event happens the method is executed.
Significantly, you can use delegates even if you don't know, at compile time, the name of the event that will invoke the delegate— the name of the event can be passed as a parameter whose value is generated during the running of the application.
In LZX, delegates and events are defined in terms of each other. A delegate is a named object that calls a method, and an event is an object which stores delegates.
When the event is generated, it calls all of its delegates in turn. A delegate can be considered, then, a named method of an instance.
Delegates that you explicitly create are generally used for objects that are created in script (that is, not by tags), although delegates can be associated with tag-generated objects as well.
               Delegates are necessary because sometimes you don't know, at compile time, what a particular event should do.  For example,
               say you have a window, and you want a certain method to be called every time the window is clicked.  In that case, you would use a tag such as
               <window onclick="clickhandler()">.  However, there may exist times when the desired action for the event depends on conditions at the time the event is created.
                In that situation you would use delegates.
            
                  To create and manage delegates, you use the lz.Delegate class.
                  
               
The syntax for creating a delegate is:
lz.Delegate(object, method, sender, event)
The 3rd and 4th optional arguments to lz.Delegate are just shorthand:
var del = new lz.Delegate(object, method, sender, event);
is the same as:
var del = new lz.Delegate(object, method); del.register(sender, event);
                  The lz.Delegate class is used to create delegates in script. 
                  
               
That is to say, you can statically attach a handler to an event by:
    <handler name="eventName" reference="eventSender">
       ...what to do...
    </handler>
                  but if you don't know eventName or eventSender at compile time, you need to use the dynamic technique:
                  
               
     <method name="methodName" args="value=null">
       ...what to do...
     </method>
     <method name="createDelegate>
     this.myDel = new lz.Delegate(this, "methodName", eventSender, "eventName");
     </method>
| ![[Note]](images/note.png) | Note | 
|---|---|
| The method referenced by a delegate must accept an argument. Most times this requirement is fulfilled by adding an optional argument to the method. | 
An event handler automatically handles all the work of making and registering a delegate for you:
onclick="do something or other;"
expands to:
<handler name="onclick" > do something or other; </name>
Which expands to:
// make a method with a unique name to run the onclick code <method name="$m<unique id>" args="ignore=null"> do something or other; </method> // make a delegate for that method var del = new lz.Delegate(this, $m<unique id>); // register it to receive onclick events del.register(this, 'onclick');
The following example is a simple memory game. When a button is clicked once, nothing special is reported. If a button is clicked a second time, the green status bar reports a message stating this fact. The game can be started over by clicking the 'start over' button.
                  Notice that for each button, when the onclick event is fired, the regbutton()
                  method is invoked on the canvas.  The regbutton() method creates a delegate for
                  the buttonclickedagain() method if no such delegate already exists, and then registers
                  the 'onclick' event of the button that has just been clicked. 
                  
               
                      If a button that
                     hasn't been clicked before is clicked, nothing special is reported (although the delegate is created). However,
                     when a
                     previously clicked button is clicked,
                     the delegate calls buttonclickedagain() which prints
                     the message stating this fact.  This is because buttons that have already been clicked have had their 'onclick' events 'registered
                     with' (or bound to) the delegate.
                  
Clicking on the 'start over' button unregisters all events from the delegate, and resets the message to nothing special.
Example 30.1. Registering an event at runtime
<canvas height="100" width="100%"> 
    <view width="80"> 
        <button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/>
        <button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/>
        <button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/>
        <button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/>
        <button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/>
        <button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/>
        <button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/>
        <button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/>
        <button width="20" height="20" onclick="canvas.regbutton(this)" onmousedown="canvas.reset()"/>
        <wrappinglayout/>
    </view> 
    <text id="statusText" bgcolor="green" resize="true"/> 
    <button text="start over" onclick="canvas.startover()"/>
    <simplelayout axis="y"/>
    <method name="regbutton" args="b"> 
        if( typeof this.del == "undefined" )  {
            this.del = new lz.Delegate( this, "buttonclickedagain" ); 
        }      
        this.del.register( b, "onclick" );
    </method> 
    <method name="startover">
        this.del.unregisterAll(); 
        this.reset();
    </method>
    <method name="reset"> 
        statusText.setAttribute("text", "Nothing special");
    </method> 
    <method name="buttonclickedagain" args="ignore=null"> 
        statusText.setAttribute("text", "That button was clicked two or more times");
    </method> 
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008, 2010 Laszlo Systems, Inc.  All Rights Reserved.       *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                        In the past, it was necessary to manually track delegates and manually clean them up when objects were destroyed to prevent memory leaks. This is no longer required - the event system now automatically cleans up delegates as needed.
 
               In the following example, a visual timer is created which shows each passing
               second.   When the <text>
               
                node is initialized, we call the
               updateTimer() method.  updateTimer() first updates the text showing to indicate
               the number of seconds passed, and then increments the secondsPassed attribute.
               The first time updateTimer() is invoked, a new delegate is created which simply
               calls updateTimer(),  and a timer is created which in turn calls the newly
               created delegate after 1 second.   Each subsequent time updateTimer() is invoked
               by the delegate, instead of creating a new timer (which would be inefficient) , lz.Timer.resetTimer() is invoked.    
               
            
Example 30.2. Using lz.Timer to create a second timer
<canvas height="20" width="100%">
    <text oninit="updateTimer()">
        <attribute name="secondsPassed" type="number" value="0"/> 
        <method name="updateTimer" args="time=null">
            this.setAttribute('text', this.secondsPassed );
            this.secondsPassed++; 
            if( typeof this.del == "undefined" ) { 
                this.del = new lz.Delegate( this, "updateTimer" );
                lz.Timer.addTimer( this.del, 1000 );
            } else {
                lz.Timer.resetTimer( this.del, 1000 );
            }
        </method>
    </text> 
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2008, 2010 Laszlo Systems, Inc.  All Rights Reserved.             *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                  
               In the following example, when the last <text> object has been
               replicated and initialized, we set the text in the green <text> to 'The last
               view has been replicated'.  To accomplish this task, we first explicitly declare 
               a datapath on the <text> to be replicated.  Next, we handle
               the onclones event, which indicates that the new <text> nodes
               has been cloned, but not initialized.  Inside the onclones event, we determine the
               last replicated clone, and register the oninit event using lz.Delegate.  When the
               last <text> node has been initialized, the delegate calls the
               "replicationComplete" method, where the text of the green <text> node is updated. 
               
            
 
               This technique can also be used to detect when the last view has loaded its
               resource by simply registering the onload event instead of the oninit event.  
               
            
Example 30.3. Registering for an event when the last view has been replicated
<canvas height="150" width="100%">
    <dataset name="people">
        <people> 
            <person name="John"/> 
            <person name="Eric"/> 
            <person name="Andrew"/> 
            <person name="chrisk"/> 
            <person name="Sarah"/> 
            <person name="Pablo"/> 
            <person name="Adam"/> 
        </people>
    </dataset> 
    <view>
        <text>
            <datapath xpath="people:/people/person/@name">
                <handler name="onclones">
                    var lastclone = this.clones[ this.clones.length - 1 ];
                    if( typeof this.del == "undefined" ) {
                        this.del = new lz.Delegate( this, "replicationComplete") 
                    } else {
                        this.del.unregisterAll();
                    }
                    this.del.register( lastclone, "oninit"); 
                </handler>
                <method name="replicationComplete" args="ignore=null">
                    lastRepText.setAttribute("text", "The last view has been replicated"); 
                </method>
            </datapath>
        </text>
        <simplelayout axis="y"/>
    </view>
    <text id="lastRepText" bgcolor="green" resize="true"> 
        Replication incomplete
    </text>
   
    <simplelayout axis="y"/> 
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2008, 2010 Laszlo Systems, Inc.  All Rights Reserved.             *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                  A delegate is an object, and as such it can be an attribute of another object. For example, consider:
Example 30.4. delegate as attribute
<button text="clickme">
    <attribute name="mydel" type="expression"
               value="$once{new lz.Delegate(this, 'handler')}"
               The above code creates the delegate mydel when the button is instantiated. This technique of declaring a delegate has the advantage of being easy to read, and it ensures
               that only one delegate is created.
               
            
For an example that uses this technique, see Chapter 45, OpenLaszlo RPC.
Here is a brief discussion of delegates in relation to other programming languages with which you may be familiar. You don't need to follow this discussion in order to use delegates in LZX.
A delegate is a 'method pointer'. It's a way of saying: "give me a thing that when I call it will call method m on object o." (As opposed to a function pointer, which doesn't capture the object.) In Java, you use an 'anonymous inner class' to get this effect (i.e., Java creates an instance with a function). In Lisp, you use a closure (i.e., Lisp creates a function with a context). [The Java and Lisp ways are just two sides of the same coin.]
Basically:
 // constructor 
 lz.Delegate = function(o, m) { this.o = o; this.m = m; } 
 lz.Delegate.prototype.execute = function () { with (this) { return o[m](); } }; 
 var del = new lz.Delegate(object, 'method'); 
 del.execute(); 
is the same as:
 // constructor 
 function makeDelegate (o, m) { return function () { return o[m](); }; }; 
 var del = makeDelegate(object, 'method'); 
 del(); 
Here you can see the parallel between allocating an instance that captures the context 'o' and 'm' and has a function (method) to invoke it, and a function that you can invoke that captures the context 'o' and 'm' by being a closure.
Copyright © 2002-2010 Laszlo Systems, Inc. All Rights Reserved. Unauthorized use, duplication or distribution is strictly prohibited. This is the proprietary information of Laszlo Systems, Inc. Use is subject to license terms.