Eventhandling, preserving Scope with Closures?

Discussion in 'Javascript' started by Marc Tanner, Jun 30, 2004.

  1. Marc Tanner

    Marc Tanner Guest

    Hello,

    I am currently working on a eventhandling system or something similar,
    and have the problem of loosing scope. I have read many interesting
    posts on this group and the faq article about closure, but it seems
    that i have still not understood everything. Below is my attempt to
    preserve the scope but it's not really nice and i think with the use
    of closure could it be done better. But at the moment i am quite
    confused and hope that someone can give me a hint...

    Another problem is that different browser have different ways of
    walking through a for-in loop, and so the functions are called in
    different sequences. Any idea how the js-engine handles a for-in loop?

    any ideas, comments, recommendations are welcome...

    <html>
    <head>
    <script type="text/javascript">

    HTMLElement = function (type) {
    this.node = typeof type == "string"
    ? document.createElement(type) : type;
    this.events = {};
    };

    HTMLElement.prototype.initEvent = function(event) {
    this.events[event] = {};
    /*
    self is a reference which gives us the ability
    to access the object from the inner function below
    */
    var self = this;
    this[event] = function (e) {
    e = e || window.event;
    for (var x in self.events[event]) {
    if (typeof self.events[event][x] == "function") {
    self.events[event][x](e, this);
    } else if (typeof self.events[event][x][x] == "function") {
    self.events[event][x][x](e, this);
    }
    }
    };

    this.node[event] = this[event];
    };

    HTMLElement.prototype.attachEvent = function(event, obj, name) {
    if (!this.events[event]) {
    this.initEvent(event);
    }
    if (typeof obj == "object" && typeof name == "string") {
    this.events[event][name] = obj;
    } else if (typeof obj == "string" && typeof name == "function") {
    this.events[event][obj] = name;
    }
    };

    HTMLElement.prototype.removeEvent = function(event, name) {
    if (this.events[event] && this.events[event][name]) {
    delete this.events[event][name];
    }
    };

    var myDemoClass = function (a, b) {

    var self = this;

    this.a = a;
    this.b = b;

    /* private function */

    var alertAandB = function (){
    alert(self.a+" "+self.b);
    };

    this.output = new HTMLElement(document.body);
    this.output.attachEvent("onclick", this, "alertA");
    this.output.attachEvent("onclick", this, "alertB");
    this.output.attachEvent("onclick", "alertAandB", alertAandB);
    };

    /* 2 public methods */

    myDemoClass.prototype.alertA = function() {
    alert(this.a);
    };

    myDemoClass.prototype.alertB = function() {
    alert(this.b);
    };

    this.onload = function() {
    myDemoInstance = new myDemoClass("Hello", "World");
    };

    </script>
    </head>
    <body>
    click me
    </body>
    </html>
    Marc Tanner, Jun 30, 2004
    #1
    1. Advertising

  2. Marc Tanner wrote:
    > I am currently working on a eventhandling system or something similar,


    If you cannot decide what your are building how will you be able to tell
    when your have finished?

    > and have the problem of loosing scope.


    Scope or object instance associations?

    > I have read many interesting
    > posts on this group and the faq article about closure,
    > but it seems that i have still not understood everything.
    > Below is my attempt to
    > preserve the scope but it's not really nice and i think
    > with the use of closure could it be done better.


    Yes, that code is inelegant, but then it seems to be doing what it
    purports to do, which makes it an inadequate explanation of what
    constitutes a problem in this context.

    > But at the moment i am quite
    > confused and hope that someone can give me a hint...


    That works both ways. Can you give a hint about what it is that is
    confusing you? You could, for example, start by explaining how you
    understand closures to work. That may then become the subject for
    comment, correction, additional explanation and examples.

    > Another problem is that different browser have different ways of
    > walking through a for-in loop, and so the functions are called in
    > different sequences. Any idea how the js-engine handles a for-in loop?


    The ECMA specification says "The mechanics of enumerating the properties
    .... is implementation dependent." So the order cannot be assumed or
    relied upon in a web browser context.

    > any ideas, comments, recommendations are welcome...
    >
    > <html>
    > <head>
    > <script type="text/javascript">
    >
    > HTMLElement = function (type) {

    ^^^^^^^^^^^
    Absolutely do not give any of your object constructors, functions or
    global variables names that correspond with W3C DOM defined interfaces
    as Mozilla/Gecko browsers make objects with those names available as
    properties of the global object and there will be naming conflicts and
    resulting unpredictable behaviour.

    > this.node = typeof type == "string"
    > ? document.createElement(type) : type;
    > this.events = {};
    > };
    >
    > HTMLElement.prototype.initEvent = function(event) {
    > this.events[event] = {};
    > /*
    > self is a reference which gives us the ability
    > to access the object from the inner function below
    > */
    > var self = this;
    > this[event] = function (e) {
    > e = e || window.event;
    > for (var x in self.events[event]) {
    > if (typeof self.events[event][x] == "function") {
    > self.events[event][x](e, this);
    > } else if (typeof self.events[event][x][x] == "function") {
    > self.events[event][x][x](e, this);
    > }
    > }
    > };
    >
    > this.node[event] = this[event];


    I don't see any need for - this[event] -, it is never used elsewhere so
    I can't see any reason for not assigning the inner function directly
    to - this.node[event] -.

    <snip>
    > this.output = new HTMLElement(document.body);
    > this.output.attachEvent("onclick", this, "alertA");
    > this.output.attachEvent("onclick", this, "alertB");
    > this.output.attachEvent("onclick", "alertAandB", alertAandB);
    > };

    <snip>
    > this.onload = function() {
    > myDemoInstance = new myDemoClass("Hello", "World");

    <snip>

    So the output should be an alert saying "Hello", an alert saying "World"
    and an alert saying "Hello World", but not necessarily in that order.
    And that is what does happen; the scope seems to be working and the -
    this - associations seem to be working.

    If you want suggestions on alternative implementations you will have to
    provide something approaching a specification for the task or a
    description of the problem that it is attempting to solve. Lots of
    implementations might be something similar to an event handling system,
    few would really be applicable to your situation.

    Richard.
    Richard Cornford, Jun 30, 2004
    #2
    1. Advertising

  3. Marc Tanner

    Marc Tanner Guest

    "Richard Cornford" <> wrote in message news:<cbulim$6lt$1$>...
    > Marc Tanner wrote:
    > > I have read many interesting
    > > posts on this group and the faq article about closure,
    > > but it seems that i have still not understood everything.
    > > Below is my attempt to
    > > preserve the scope but it's not really nice and i think
    > > with the use of closure could it be done better.

    >
    > Yes, that code is inelegant, but then it seems to be doing what it
    > purports to do, which makes it an inadequate explanation of what
    > constitutes a problem in this context.
    >


    Yes, it does what it should, but i can't figure out a solution with
    closure which does the same and is elegant.

    > > But at the moment i am quite
    > > confused and hope that someone can give me a hint...

    >
    > That works both ways. Can you give a hint about what it is that is
    > confusing you? You could, for example, start by explaining how you
    > understand closures to work. That may then become the subject for
    > comment, correction, additional explanation and examples.
    >


    Well i think the main goal of using closure is that a function has
    access to all private member of it's outer function(s) even when it's
    already returned.

    > > Another problem is that different browser have different ways of
    > > walking through a for-in loop, and so the functions are called in
    > > different sequences. Any idea how the js-engine handles a for-in loop?

    >
    > The ECMA specification says "The mechanics of enumerating the properties
    > ... is implementation dependent." So the order cannot be assumed or
    > relied upon in a web browser context.
    >


    So i have to use scalar arrays instead another problem...

    > > any ideas, comments, recommendations are welcome...
    > >
    > > <html>
    > > <head>
    > > <script type="text/javascript">
    > >
    > > HTMLElement = function (type) {

    > ^^^^^^^^^^^
    > Absolutely do not give any of your object constructors, functions or
    > global variables names that correspond with W3C DOM defined interfaces
    > as Mozilla/Gecko browsers make objects with those names available as
    > properties of the global object and there will be naming conflicts and
    > resulting unpredictable behaviour.
    >


    OK, i totally agree.

    > > this.node = typeof type == "string"
    > > ? document.createElement(type) : type;
    > > this.events = {};
    > > };
    > >
    > > HTMLElement.prototype.initEvent = function(event) {
    > > this.events[event] = {};
    > > /*
    > > self is a reference which gives us the ability
    > > to access the object from the inner function below
    > > */
    > > var self = this;
    > > this[event] = function (e) {
    > > e = e || window.event;
    > > for (var x in self.events[event]) {
    > > if (typeof self.events[event][x] == "function") {
    > > self.events[event][x](e, this);
    > > } else if (typeof self.events[event][x][x] == "function") {
    > > self.events[event][x][x](e, this);
    > > }
    > > }
    > > };
    > >
    > > this.node[event] = this[event];

    >
    > I don't see any need for - this[event] -, it is never used elsewhere so
    > I can't see any reason for not assigning the inner function directly
    > to - this.node[event] -.


    Right, until now it's not used but it could be useful if i want to
    fire the event by myself.

    > <snip>
    > > this.output = new HTMLElement(document.body);
    > > this.output.attachEvent("onclick", this, "alertA");
    > > this.output.attachEvent("onclick", this, "alertB");
    > > this.output.attachEvent("onclick", "alertAandB", alertAandB);
    > > };

    > <snip>
    > > this.onload = function() {
    > > myDemoInstance = new myDemoClass("Hello", "World");

    > <snip>
    >
    > So the output should be an alert saying "Hello", an alert saying "World"
    > and an alert saying "Hello World", but not necessarily in that order.
    > And that is what does happen; the scope seems to be working and the -
    > this - associations seem to be working.
    >
    > If you want suggestions on alternative implementations you will have to
    > provide something approaching a specification for the task or a
    > description of the problem that it is attempting to solve. Lots of
    > implementations might be something similar to an event handling system,
    > few would really be applicable to your situation.


    Ok, it should be possible to associate several functions/methods from
    different classes (i know JS doesn't really have classes) with the
    same event of an (x)HTML-node. Calling the methods in a way that this
    is pointing to the right object/instance. Further should it be done as
    elegant as possible ;)

    > Richard.


    thanks for your effort

    Marc
    Marc Tanner, Jul 1, 2004
    #3
  4. Marc Tanner wrote:
    > Richard Cornford wrote:

    <snip>
    >> That works both ways. Can you give a hint about what it is that is
    >> confusing you? You could, for example, start by explaining how you
    >> understand closures to work. That may then become the subject for
    >> comment, correction, additional explanation and examples.
    >>

    >
    > Well i think the main goal of using closure is that a function has
    > access to all private member of it's outer function(s) even when it's
    > already returned.


    Where closures only are concerned you probably don't want to be talking
    in terms of private members. The items that the inner function has
    access to are the function declarations, local variables and formal
    parameters from its containing functions. They only become 'private
    members' if that is the concept that is being implemented (i.e. some
    sort of object).

    >>> Another problem is that different browser have different ways of
    >>> walking through a for-in loop, and so the functions are called in
    >>> different sequences. Any idea how the js-engine handles a for-in
    >>> loop?

    >>
    >> The ECMA specification says "The mechanics of enumerating the
    >> properties ... is implementation dependent." So the order cannot be
    >> assumed or relied upon in a web browser context.

    >
    > So i have to use scalar arrays instead another problem...


    Not necessarily. One of my earliest applications of closures was in
    making stacks of functions. Previously I had been assembling chains of
    object instances with 'next' and 'previous' relationships and having
    each call its 'next' (or 'previous') so that execution could ripple
    through an indefinitely long structure of like-objects.

    Closures (and scope chain augmentation) allow similar structures, often
    more simply, and with the advantage that the 'objects' in the chain are
    functions so the 'object' can be called itself instead of calling a
    method on that object. The procedure is also flexible enough to allow
    other structures such as trees, where execution of a node will ripple
    execution back to the root, for example. And a combination of closures,
    scope chain augmentation and function properties referring to related
    nodes allows the same structure to act as a tree and two stack/lists
    with different ordering at the same time (though mostly there is no
    need).

    The stacks represent stacks of call-back function rather than object
    instances so the callback functions themselves need implement any
    associations with other objects they are interested in. The call-back
    functions also need to satisfy some sort of contract (be of a like form
    and behaviour) so that the stacking functions can know how to handle
    them, pass parameters, ect.

    The following are two such function stacks. The contract that the
    call-back functions need to fulfil is that they should not expect more
    than one parameter (as passed on from the call to the function that acts
    as the object representing the stack, and that they provide a return
    value. That return value should be - true - if the callback function
    want to say in the stack and false if it wants to be removed (has done
    its job). I use this style of contract a great deal with this type of
    function stack because it avoids needing an explicit - removeFunction -
    method to be implemented on the function object that represents the
    stack.

    The execution order of the two implementations is first in last called
    (FILC) and first in first called (FIFC). More complex implementation may
    allow for the re-ordering of such a stack, under external control or as
    a consequence of its operation, but that is not relevant here.

    function getNewFILCFncStac(fnc){
    function getNewStackFnc(f){
    var next = null;
    function t(a){
    next = next&&next(a);
    return (f(a))?t:next;
    }
    t.addItem = function(d){
    if(f != d){
    if(next){
    next.addItem(d);
    }else{
    next = getNewStackFnc(d);
    }
    }
    return this;
    };
    return t;
    }
    var base = getNewStackFnc(fnc);
    fnc = function(a){
    base = base&&base(a);
    };
    fnc.addItem = function(d){
    if(base){
    base.addItem(d)
    }else{
    base = getNewStackFnc(d);
    }
    };
    return fnc;
    }

    function getNewFIFCFncStac(fnc){
    function getNewStackFnc(f, next){
    function t(a){
    next = next&&next(a);
    return (f(a))?t:next;
    }
    return t;
    }
    var base = getNewStackFnc(fnc, null);
    fnc = function(a){
    base = base&&base(a);
    };
    fnc.addItem = function(d){
    base = getNewStackFnc(d, base);
    };
    return fnc;
    }

    Their operation is to call, say, - getNewFIFCFncStac - and pass a
    reference to a callback function as the argument. The function object
    returned is then assigned to something; private member, object property,
    event handler, etc., from where it can be executed. But that function
    object also provides an - addItem - method that can be used to add
    additional call-back functions to the stack.

    An example application of one of these stacks is:-

    function resizeMonitor(fnc){
    var fncStack,global = this;
    function main(funcRef){
    if(funcRef){
    fncStack.addItem(funcRef);
    globalCheck();
    }
    }
    function globalCheck(){
    if(global.onresize != fncStack){
    if(global.onresize){
    fncStack.addItem(oldHandler(global.onresize));
    }
    global.onresize = fncStack;
    }
    }
    function retFalse(){return false;}
    function oldHandler(f){return (function(e){f(e);return true;});}
    fncStack = getNewFILCFncStac(fnc);
    if(global.addEventListener){
    global.addEventListener("resize", fncStack, false);
    globalCheck = retFalse;
    }else if(global.attachEvent){
    global.attachEvent("onresize", fncStack);
    globalCheck = retFalse;
    }
    global.resizeMonitor = main
    }

    Which allows an indefinite number of call-back functions to be executed
    when window.onresize events occur. I say indefinite but in reality the
    main drawback of function stacks is that they can produce (internal)
    stack overflow errors if they get too big, or the callback functions
    attempt to call too many other functions themselves. In practice you
    have to create a fairly big (500+ items) function stack before that is a
    problem, and usually that is well beyond what any application requires.

    <snip>
    >> If you want suggestions on alternative implementations you will have
    >> to provide something approaching a specification for the task or a
    >> description of the problem that it is attempting to solve. Lots of
    >> implementations might be something similar to an event handling
    >> system, few would really be applicable to your situation.

    >
    > Ok, it should be possible to associate several functions/methods from
    > different classes (i know JS doesn't really have classes) with the
    > same event of an (x)HTML-node. Calling the methods in a way that this
    > is pointing to the right object/instance. Further should it be done as
    > elegant as possible ;)


    One of the questions in OO design is to determine the best demarcation
    between the objects used. Wanting a facility for any
    instance of any class (we can accept the OO terminology here as a
    convenient shorthand for broadly analogous concepts) to attach a
    listener, that may be a method of a specific object, to any event
    handler on any DOM element, means that the classes using the
    facility should not have any interest in the implementation of the
    facility; it should be a simple common interface that is globally
    available when needed.

    In your original code you are trying to handle both callback functions
    and calling methods on specific object instances. Overall I think these
    two activities can (and so probably should) be separated. That is, I
    would want the interface to the event handlers to be interested in
    callback functions and have a separate mechanism that allowed the
    callback functions to call methods on associated object instances. That
    will involve wrapping the object instance and methods to call
    information in a closure that returned a function that would then act as
    the callback function.

    I would also implement the event handler removal using function
    references, which is going to hand a little more work back to the
    classes using the facility to call their own instance method because
    they will have to keep a reference to the callback function that is
    wrapping the call to each of their methods if they want to use the
    facility to remove event listeners by reference.

    One of the main reasons that I would choose this separation is that it
    would make it relatively easy for the event listener handling
    implementation to employ the DOM Events - add/removeEventListener - as
    its primary mechanism and only use the intrinsic event handlers as a
    fall-back. Allowing the intrinsic event aspects of the code to be
    dropped entirely in the future if DOM Events becomes universally
    supported in browsers in use, without the need to modify any of the code
    for the classes using the facility. For that reason I will also be using
    the shorter event names, without the 'on' prefix, in discussing the
    interfaces. However, I will not actually employ -
    add/removeEnventListener - in any of the following code.

    Using a Java style public constructor-less class with public static
    methods forming the interface seems like a reasonable implementation. So
    a global variable named - EventHandling - (or as you like it) will have
    the methods - addListner - and - removeListener -, and each method will
    expect the arguments - domElement -, - eventName - and - callBackFnc -.
    eventName being the short form without the 'on' prefix.

    (Incidentally, there is no way that your original code should have been
    creating a DOM element when it was not passed one by reference. That
    gave you HTMLElement object an extremely strange duel role.)

    Next we need to decide on the contract for - callBackFnc -; It is going
    to be an event handler (at least triggered by one) so the event object
    is an obvious candidate as an argument. It is also likely to be
    interested in which domElement it was called from so that should
    additionally be an argument for - callBackFnc. In this case we have
    a - removeListener - method for detaching callback functions so the
    return value from the callback function can do a different job. But we
    are dealing with intrinsic events so return values may cancel default
    actions; We will attempt to employ the return values from -
    callBackFnc - in this way, but we will also _specify_ that the -
    EventHandling - system does not get involved in calling
    event.preventDefault or event.stopPropagation, or in setting
    event.cancelBubble or event.returnValue. Those operations are left the
    responsibility of the callback function itself (or the instance methods
    it calls). The callback functions are specified as _always_ returning a
    boolean value, - true - if they are not attempting to cancel the default
    action.

    At this point it is possible to implement a function that will create
    callback functions that calls a particular method on an object instance
    to satisfy the needs of classes wishing to employ the - EventHandling -
    facility. The instances of such classes will need to keep a reference to
    the returned callback function object if they intend to use -
    removerListener - at some later point. And the method called is expected
    to provide the boolean return value.

    function associateObjInstanceMethodWithCallBackFunction(obj methodName){
    return (fucntion(e, domElement){
    return obj[methodName](e, domElement);
    });
    }

    The function returned from a call to this method satisfies the contract
    for the callback function and will call a named method on the object
    referred to by the - obj - parameter when it is executed, passing its
    event and domElement arguments on to that method, and returning whatever
    (boolean) value that method returns.

    The return values from intrinsic event handlers can be problematic. For
    an onclick event, for example, returning true or not returning anything
    at all (undefined) allows the default action. Only returning boolean
    false (or something that will type-convert to boolean false other than
    undefined) will cancel the default action. This is also true of -
    onsubmit - but not necessarily true for all events that may be used (I
    can't think of an example right now). That may be a problem for a
    general event handling system, but I don't intend addressing it here. My
    strategy will be to create a default - true - return value and then AND
    it with the return value form each callback function. The effect will be
    that if any return - false - false will be returned, otherwise the
    default - true - will be returned.

    Another problem with a generalised method is that it is going to have to
    attempt to handle the actions of other scripts and of HTML authors. Any
    element may already have an event handler and that handler is unlikely
    to satisfy the contract for our callback functions. This is one of the
    reasons for preferring the DOM Events - add/removeEventListener -
    approach as it allows additional listeners to be associated with the
    events on elements without any concern for pre-existing handlers.

    All we can hope to do about pre-existing handlers is wrap them in a
    function that satisfies our callback function contract and calls the
    original handler in a way that resembles how it would otherwise have
    been called. That involves using Function.prototype.call or
    Function.prototype.apply (preferably - call - in this context). However,
    using intrinsic event implies a system that will work on older browsers,
    but some older browsers do not implement - call - or - apply -. This
    problem can be handled with a - call - or - apply - emulation function.
    I will not be including one here but examples may be found by searching
    the comp.lang.javascript archives at groups.google.com.

    Another problem with pre-existing event handlers is going to be their
    return values. ANDing their return value with the default will not be
    sufficient as an undefined return value is possible (our callback
    function contract requires a boolean return value always). It will be
    necessary to check the value returned for a call to an original event
    handler and ensure that it is not undefined before ANDing it with the
    default, otherwise an undefined value will need to be converted to true.

    Obviously another script might still overwrite a handler assigned with -
    EventHandling - with one of its own, but that highlights the stupidity
    of attempting to mix scripts from various sources on the same page
    without understanding how they work.

    The preceding text is probably sufficiently close to being a
    specification that - EventHandling - can be implemented from it so here
    goes:-

    var EventHandling = (function(){
    var global = this;
    var onName = ['on',''];
    function getNewFncStac(fnc){
    function getStackFnc(f){
    var next = null;
    function t(e, domElement){
    /* Swap the next two lines to have the stack execute
    in reverse order (currently FILC):-
    */
    (next&&next(e, domElement));
    var ret = f(e, domElement);
    fnc.defalutReturn = ret && fnc.defalutReturn;
    }
    t.addItem = function(d){
    if(f != d){ // don't add duplicates
    if(next){
    next.addItem(d);
    }else{
    next = getStackFnc(d);
    }
    }
    };
    t.removeItem = fucntion(d){
    if(f == d){
    f = null;
    return next;
    }else if(next){
    next = next.removeItem(d);
    }
    return this;
    }
    return t;
    }
    var base = getStackFnc(fnc);
    fnc = function(e){
    e = e||global.event;
    fnc.defalutReturn = true;
    (base&&base(e, this));
    return fnc.defalutReturn;
    };
    fnc.addItem = function(d){
    if(base){
    base.addItem(d)
    }else{
    base = getStackFnc(d);
    }
    };
    fnc.removeItem = function(d){
    base = base&&base.removeItem(d);
    };
    fnc.defalutReturn = true;
    return fnc;
    }
    function getPresevationWraper(original){
    return (function(e, domElement){
    var ret = original.call(domElement, e);
    return ((typeof ret == 'undefined')||Boolean(ret));
    });
    }
    return ({
    addListner:function(domElement, eventName, callBackFnc){
    var evName, hndlr;
    if(domElement && eventName && callBackFnc){
    onName[1] = eventName;
    evName = onName.join('');
    hndlr = domElement[evName];
    if(hndlr){
    if(hndlr.addItem){
    hndlr.addItem(callBackFnc);
    }else{ //not one of our handlers.
    (domElement[evName] = getNewFncStac(
    getPresevationWraper(hndlr)
    )).addItem(callBackFnc);
    }
    }else{
    domElement[evName] = getNewFncStac(callBackFnc);
    }
    }
    },
    removeListener:function(domElement, eventName, callBackFnc){
    var evName, hndlr;
    if(domElement && eventName && callBackFnc){
    onName[1] = eventName;
    evName = onName.join('');
    hndlr = domElement[evName];
    if(hndlr && hndlr.removeItem){
    hndlr.removeItem(callBackFnc);
    }
    }
    }
    });
    })();

    /*
    Called as:-

    EventHandling.addListner(domElement, eventName, callBackFnc);

    - and:-

    EventHandling.removeListener(domElement, eventName, callBackFnc);

    - and from object instances as (for example):-

    this[methodName].callBack =
    associateObjInstanceMethodWithCallBackFunction(this, methodName);

    - with:-

    EventHandling.addListner(
    domElement,
    eventName,
    this[methodName].callBack
    );

    - and:-

    EventHandling.removeListener(
    domElement,
    eventName,
    this[methodName].callBack
    );
    this[methodName].callBack = null;

    Remembering that the - eventName - is the shorter version without the
    'on' prefix.

    */

    Untested, but nothing stands out as wrong to me. If you have questions,
    ask.

    If the system was intended to be used exclusively, or mostly, to call
    instance methods then it might make a lot as sense to have the -
    associateObjInstanceMethodWithCallBackFunction - function on the -
    EventHandling - interface. otherwise it may be regarded as a utility
    that could be employed in other contexts where a callback function was
    wanted that would call an instance method, but where contract of the
    callback function was either satisfactory or unimportant.

    Richard.
    Richard Cornford, Jul 1, 2004
    #4
  5. Marc Tanner

    Marc Tanner Guest

    "Richard Cornford" <> wrote in message news:<cc1bc9$4ff$1$>...

    Great stuff, it is quite another style of programming and it may take
    a moment to become familiar with it, but i think that i have
    understood the main things. Otherwise i will ask again...

    > One of the questions in OO design is to determine the best demarcation
    > between the objects used. Wanting a facility for any
    > instance of any class (we can accept the OO terminology here as a
    > convenient shorthand for broadly analogous concepts) to attach a
    > listener, that may be a method of a specific object, to any event
    > handler on any DOM element, means that the classes using the
    > facility should not have any interest in the implementation of the
    > facility; it should be a simple common interface that is globally
    > available when needed.
    >
    > In your original code you are trying to handle both callback functions
    > and calling methods on specific object instances. Overall I think these
    > two activities can (and so probably should) be separated. That is, I
    > would want the interface to the event handlers to be interested in
    > callback functions and have a separate mechanism that allowed the
    > callback functions to call methods on associated object instances. That
    > will involve wrapping the object instance and methods to call
    > information in a closure that returned a function that would then act as
    > the callback function.


    The reason why i was trying to handle both things in the same method
    is that i would like to keep it simple for the end user. The code here
    is acting as a basic library, that means that there will (hopefully)
    be a few people using it. So i tend to solve the problem with a
    all-in-one solution, the perfect thing would be if the call could be
    done with something like that:

    [XHTMLElementInstance].addEventlistener("event",function_reference);

    > One of the main reasons that I would choose this separation is that it
    > would make it relatively easy for the event listener handling
    > implementation to employ the DOM Events - add/removeEventListener - as
    > its primary mechanism and only use the intrinsic event handlers as a
    > fall-back. Allowing the intrinsic event aspects of the code to be
    > dropped entirely in the future if DOM Events becomes universally
    > supported in browsers in use, without the need to modify any of the code
    > for the classes using the facility. For that reason I will also be using
    > the shorter event names, without the 'on' prefix, in discussing the
    > interfaces. However, I will not actually employ -
    > add/removeEnventListener - in any of the following code.


    The application is just avalaible for DOM-compatible Browser so i
    could use add/removeEventListener.

    > Using a Java style public constructor-less class with public static
    > methods forming the interface seems like a reasonable implementation. So
    > a global variable named - EventHandling - (or as you like it) will have
    > the methods - addListner - and - removeListener -, and each method will
    > expect the arguments - domElement -, - eventName - and - callBackFnc -.
    > eventName being the short form without the 'on' prefix.
    >
    > (Incidentally, there is no way that your original code should have been
    > creating a DOM element when it was not passed one by reference. That
    > gave you HTMLElement object an extremely strange duel role.)


    Well normally it does create DOM elements but i didn't want to include
    that in my example. In fact we start with a blank page an then we
    start to add DOM elements. For better understanding you may visit
    http://free.pages.at/giftzwerg/webos0.1/webos.html

    I know it's bad coding-style and there are many bugs, but until now I
    didn't have the time to correct it and to wirte it better...

    <snipped out really good stuff>

    > If the system was intended to be used exclusively, or mostly, to call
    > instance methods then it might make a lot as sense to have the -
    > associateObjInstanceMethodWithCallBackFunction - function on the -
    > EventHandling - interface.


    Yes i think it makes sense...

    > Richard.


    Again thanks for spending your time, i will take a closer look on this
    article later (at the moment i am quite busy).

    Marc
    Marc Tanner, Jul 5, 2004
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Andrea
    Replies:
    0
    Views:
    370
    Andrea
    Dec 18, 2003
  2. Claes Rådström
    Replies:
    3
    Views:
    338
    Claes Rådström
    Feb 5, 2004
  3. Herfried K. Wagner [MVP]
    Replies:
    12
    Views:
    564
    =?Utf-8?B?YmFsbWVyY2g=?=
    Dec 1, 2005
  4. TTroy
    Replies:
    16
    Views:
    787
    Peter Nilsson
    Jan 31, 2005
  5. Replies:
    4
    Views:
    518
Loading...

Share This Page