Smart Mobile Studio
  • News
  • Forums
  • Download
  • Store
  • Showcases
    • Featured demos
    • The Smart Contest 2013, Round 1 โ€“ Graphics
  • Documentation
    • Get the book
    • System requirements
    • Prerequisites
    • Getting started
      • Introduction
      • Application architecture
      • The application object
      • Forms and navigation
      • Message dialogs
      • Themes and styles
    • Project types
      • Visual project
      • Game project
      • Console project
    • Layout manager
    • Networking
      • TW3HttpRequest
      • TW3JSONP
      • Loading files
  • About

Events as objects

Posted on 18.01.2016 by Jon Lennart Posted in Developers log 5 Comments

Events are fun right? Well, only in part to be honest.ย For example, what do you do if you want to catch the same event but at different places?

This is where JavaScript’s addEventListener() comes into play. In short it allows you to add as many event-handlers to the same event as your heart desires. But raw unadulterated JavaScript is a bit of a mess, so I decided to wrap this up in clear cut objects. Oh, and I added a “fixed” event for when you want to have objects for standard events as well.

So now whenever you want to hook an event without ruining your published event-handlers (for instance in TW3CustomControl) you can just use one of these ๐Ÿ™‚

Enjoy!

unit eventobjs;

interface

uses 
  w3c.dom,
  SmartCL.Components,
  SmartCL.System;

type


  TEventObjTriggeredEvent = procedure (sender:TObject;EventObj:JEvent);

  TEventObj = class(TObject)
  private
    FOwner:     TW3TagObj;
    FAttached:  Boolean;
    FEventName: String;
  protected
    procedure   HandleEvent(eobj:variant);virtual;
  public
    Property    Attached:Boolean read FAttached;
    procedure   Attach(EventName:String);
    procedure   Detach;
    constructor Create(AOwner:TW3TagObj);virtual;
    destructor  Destroy;Override;
  public
    Property    EventName:String read FEventName;
    Property    Owner:TW3TagObj read FOwner;
    Property    OnEvent: TEventObjTriggeredEvent;
  end;

  TFixedEventObj = class(TObject)
  protected
    FAttached:  Boolean;
    FOwner:     TW3TagObj;
    procedure   HandleEvent(eobj:variant);virtual;
  protected
    function    DoGetEventName:String;virtual;abstract;
  public
    Property    Attached:Boolean read FAttached;
    procedure   Attach;
    procedure   Detach;
    constructor Create(AOwner:TW3TagObj);virtual;
    destructor  Destroy;override;
  public
    Property    Owner:TW3TagObj read FOwner;
    Property    OnEvent: TEventObjTriggeredEvent;
  end;

  TElementRemovedEvent = class(TFixedEventObj)
  protected
    function  DoGetEventName:String;override;
  end;

  TElementAddedEvent = class(TFixedEventObj)
  protected
    function  DoGetEventName:String;override;
  end;

implementation


//#############################################################################
// TElementAddedEvent
//#############################################################################

function TElementAddedEvent.DoGetEventName:String;
begin
  result := "DOMNodeInserted";
end;

//#############################################################################
// TElementRemovedEvent
//#############################################################################

function TElementRemovedEvent.DoGetEventName:String;
begin
  result := "DOMNodeRemoved";
end;

//#############################################################################
// TFixedEventObj
//#############################################################################

constructor TFixedEventObj.Create(AOwner:TW3TagObj);
begin
  inherited Create;
  FOwner:=AOwner;
  Attach;
end;

destructor TFixedEventObj.Destroy;
begin
  Detach;
  inherited;
end;

procedure TFixedEventObj.Attach;
begin
  if FAttached then
  Detach;
  FOwner.Handle.addEventListener(DoGetEventName,@HandleEvent,true);
  FAttached := true;
end;

procedure TFixedEventObj.Detach;
begin
  if FAttached then
  begin
    FOwner.Handle.removeEventListener(DoGetEventName,@HandleEvent,true);
    FAttached := false;
  end;
end;

procedure TFixedEventObj.HandleEvent(eObj:variant);
begin
  if assigned(OnEvent) then
  OnEvent(self, JEvent(eObj));
end;

//#############################################################################
// TEventObj
//#############################################################################

constructor TEventObj.Create(AOwner:TW3TagObj);
begin
  inherited Create;
  FOwner := AOwner;
end;

destructor TEventObj.Destroy;
begin
  if FAttached then
  Detach;
  inherited;
end;

procedure TEventObj.HandleEvent(eobj:variant);
begin
  if assigned(OnEvent) then
  OnEvent(self,JEvent(eObj));
end;

procedure TEventObj.Attach(EventName:String);
begin
  if FAttached then
  Detach;

  FEventName := EventName;
  try
    FOwner.handle.addEventListener(FEventName,@HandleEvent,true);
  except
    FEventname:= '';
    FAttached:=false;
    exit;
  end;
  FAttached:=true;
end;

procedure TEventObj.Detach;
begin
  if FAttached then
  begin
    try
      FOwner.handle.removeEventListener(FEventName,@HandleEvent,true);
    finally
      FEventName := '';
      FAttached := false;
    end;
  end;
end;

end.
code events HTML5 javascript Object Pascal OP4JS Pascal Smart Mobile Studio w3C
« Nullable types
Hybrid Web-Apps with Cordova »

5 thoughts on “Events as objects”

  1. Shane Holmes says:
    19.01.2016 at 01:15

    I read this three times and I am still clueless as to how they are used. Sorry! Can we get a demo of each of the Objects?

  2. Jon Lennart says:
    19.01.2016 at 07:25

    Ha ha ๐Ÿ™‚ Yeah i did write that rather quickly.

    Now, if you look in the RTL, you notice that the events we expose, like OnClick etc. are mapped directly. So whenever you assign an event-handler, that event is taken right?

    FMyComponent.OnClick := procedure (sender:TObject)
    begin
    end;

    When the event is taken then you cant add more event-handlers to it. Which sucks if you want to catch that event on many different places. By tradition, Object Pascal allows only one event-handler per event.

    Javascript however, allows several event-handlers per event. So the code above allows you to do that.

    So now you can do:

    FFirst := TEventObj.Create(w3Panel1);
    FFirst.attach(‘onclick’);
    FFirst.OnEvent := procedure (sender:TObject;EventObj:JEvent)
    begin
    end;

    FSecond:= TEventObj.Create(w3Panel1);
    FSecond.attach(‘onclick’);
    FSecond.OnEvent := procedure (sender:TObject;EventObj:JEvent)
    begin
    end;

    Voila! Now we have two event handlers for the same event! Both will kick in whenever you click on the panel ๐Ÿ™‚

    NOTE: The classes above attach to the JavaScript side of things, so event-names are case sensitive. Also, you get access to the JavaScript event object directly.

    About “TFixedEventObj”.
    This is just a class which does the same thing — but allows you to wrap events in pre-defined objects. You dont need this class if you are happy with the Attach(Eventname). You see that i have implemented two “fixed” classes, which map the OnElementInserted and OnElementRemoved, which fires on the javascript side whenever you add or remove a component from .. well, a component.

    So the first will fire when you do this:

    FChild := TW3CustomControl.Create(FParent);

    Above, the TElementAddedEvent will fire.

    FChild.free; // removes child from FParent

    And here the TElementRemovedEvent will fire.

    I just wrapped these two events for ease of use, nothing more. There is nothing magical about these

  3. Shane Holmes says:
    19.01.2016 at 14:19

    Thanks, that helped tremendously. I did not know this was possible in any event-driven language.

    • Jon Lennart says:
      27.01.2016 at 14:27

      Its standard in C#, C++, Java and JavaScript ๐Ÿ™‚

    • Jon Lennart says:
      27.01.2016 at 14:35

      Also, the main use for those are when you write custom controls.
      You dont want to kidnap the OnClick etc. events, because then the user of your component wont have any.
      With the above you can write components that act on events, and still expose the standard events without ruining anything.

      Ex:

      TMySuperPanel = class(Tw3CustomControl)
      published
      property OnClick;
      property OnMouseDown;
      end;

      In the above we expose the OnClick event and OnMouseDown which are defined in TW3CustomControl. So users can now attach their code to them. Thet remained “un-used” even though we might listen to the same events in our code (using the classes in this article)

Comments are closed.

Pages

  • About
  • Feature Matrix
  • Forums
  • News
  • Release History
  • Download
  • Showcases
    • The Smart Contest 2013, Round 1 – Graphics
  • Store
  • Documentation
    • Creating your own controls
    • Debugging, exceptions and error handling
    • Differences between Delphi and Smart
    • Get the book
    • Getting started
      • Introduction
      • Local storage, session storage and global storage
      • Application architecture
      • The application object
      • Forms and navigation
      • Message dialogs
      • pmSmart Box Model
      • Themes and styles
    • Layout manager
    • Networking
      • Loading files
      • TW3HttpRequest
      • TW3JSONP
    • Prerequisites
    • Real data, talking to sqLite
    • System requirements
    • Project types
      • Visual project
      • Game project
      • Console project

Archives

  • December 2019
  • December 2018
  • November 2018
  • July 2018
  • June 2018
  • February 2018
  • September 2017
  • April 2017
  • November 2016
  • October 2016
  • September 2016
  • April 2016
  • March 2016
  • January 2016
  • October 2015
  • September 2015
  • July 2015
  • April 2015
  • January 2015
  • December 2014
  • October 2014
  • September 2014
  • August 2014
  • July 2014
  • June 2014
  • March 2014
  • February 2014
  • January 2014
  • December 2013
  • November 2013
  • October 2013
  • August 2013
  • July 2013
  • June 2013
  • May 2013
  • April 2013
  • March 2013
  • February 2013
  • January 2013
  • December 2012
  • November 2012
  • August 2012
  • July 2012
  • June 2012
  • May 2012
  • April 2012
  • March 2012
  • February 2012
  • January 2012
  • November 2011
  • October 2011
  • September 2011

Categories

  • Announcements (25)
  • Developers log (119)
  • Documentation (26)
  • News (104)
  • News and articles (16)

WordPress

  • Register
  • Log in
  • WordPress

Subscribe

  • Entries (RSS)
  • Comments (RSS)
ยฉ Optimale Systemer AS