Jump to content

Components and how to make them data-aware


Recommended Posts

  • Moderators
A couple of links for whoever is interested in some simple SMS components :

 

1) www.lynkfs.com/components/MySQLDB/MySQLDB.pas

A cross domain component which takes a SQL query on any existing MySQL database and returns the cursor in both a local Variant and an on the fly generated TDataSet. Superfluous to have both ways implemented, but just for fun

Example of use of this component in ..../MySQLDB/TestMySQLDB.sproj

 

How to make a standard memo data-aware : just drag this component and a Memo on a form and connect them as in .../MemoDB/TestMemoDB.sproj

Preview in .../MemoDB/www/index.html

 

2) www.lynkfs.com/components/Accordeon/Accordion.pas

A collapsible panel component. Example of use in .../Accordeon/TestAccordeon.sproj

Preview in .../Accordeon/www/index.html

 

How to make this component data aware : put this component and the previous one on a form as in .../AccordeonDB/TestAccordeonDB.sproj

Preview in .../AccordeonDB/www/index.html

 

Components have been built with the latest beta.

The MySQL test database used has just 1 table with some data of just 5 customers.

 

3) For a next post  : TTreeView, TCarousel, TPageControl and TPopUpMenu

Link to post
Share on other sites

Hi, I'm playing with SmartMS, but unfortunately I couldn't find an smart way to accomplish data binding. For instance,

basically I have JavaScript object similar to: var a = {b:3}; 

I have rendered an input element like using innerHTML:

I’d like the input’s value to be a.b’s value (for example), and when the input text changes, I’d like a.b to change too. When a.b changes in SMS, the input changes. 

The Question:
Any idea how would you implement a bi-directional data-binding with SmartMS?

Link to post
Share on other sites
  • Moderators

Hi warleyalex

 

not a straightforward solution. There is a proposed object.observe function which fires in js when an objects atrribute(s) changes. However this is still experimental and not in all browsers available.

 

Best I could find is a small lib called watch.js

Download from github.com/melanke/Watch.JS/blob/master/README.md 

and add to the head of your index file :   <script src="res/watch.js"></script>

 

The bi-directional data-binding now works as follows :

- from your input element to your object is easy, just use the OnChange method on f.i. a standard EditBox

- from your object to the input element (EditBox) do this :

  - define a watcher on one or more attributes of your data object

  - when the watcher fires due to a change in data despatch a custom message (new message functions in SMS)

  - receive the message and update the EditBox

 

Coding as per below :

 

unit Form1;
 
interface
 
uses
  SmartCL.System, SmartCL.Graphics, SmartCL.Components, SmartCL.Forms,
  SmartCL.Fonts, SmartCL.Borders, SmartCL.Application, SmartCL.Controls.Label,
  SmartCL.Controls.EditBox, SmartCL.Controls.Button,
  System.Types, System.Messages;
 
type
  TForm1 = class(TW3Form)
  private
    {$I 'Form1:intf'}
  protected
    procedure InitializeForm; override;
    procedure InitializeObject; override;
    procedure ObjectReady; override;
    procedure Resize; override;
    EditBox1 : TW3EditBox;
    Button1  : TW3Button;
    Label1   : TW3Label;
    Variant1 : Variant;
    FMsgPort : TMessageSubscriber;
    FMessage1: TMessageClass;
  end;
 
implementation
 
{ TForm1 }
 
procedure TForm1.InitializeForm;
begin
  inherited;
  // this is a good place to initialize components
end;
 
procedure TForm1.InitializeObject;
begin
  inherited;
  {$I 'Form1:impl'}
 
  EditBox1 := TW3EditBox.Create(self);
  Button1 := TW3Button.Create(self);
  Button1.Caption := 'change object value';
  Label1 := TW3Label.Create(self);
  Label1.Caption := 'Type something and tab out';
  Variant1 := TVariant.CreateObject;
end;
 
 
procedure TForm1.ObjectReady;
var
  mMessage: TCustomMessage = new TCustomMessage();
begin
  inherited;
 
  asm
    //defining an initial data object
    @Variant1 = {
        a: "initial value of attr a",
        b: "initial value of attr b"
    };
 
    //watch for any change of attribute a
    //when a change happens a message is despatched
    watch(@Variant1, "a", function(){
        @PostMessage(@mMessage);
    });
 
  end;
 
// messaging setup
  FMsgPort:=TMessageSubscriber.Create;
  FMessage1:=TMessageClass.Create;
  FMsgPort.SubScribeTo(FMessage1);
 
// when message is received
  FMsgPort.OnMessage := procedure(const Sender:TMessageSubScriber; const Message:TCustomMessage)
  begin
    try
      // set editbox to new value
      EditBox1.Text := Variant1['a'];
    finally
      message.done;
    end;
  end;
 
  Button1.OnClick := procedure(Sender: TObject)
    begin
    //when changing the objects attribute its watcher will be invoked
      Variant1['a'] := 'a new object value';
    end;
 
  EditBox1.OnChanged := procedure(Sender: TObject)
    begin
      Variant1['a'] := EditBox1.Text;
      ShowMessage('Object value changed to ' + Variant1['a']);
    end;
 
end;
 
procedure TForm1.Resize;
begin
  inherited;
  EditBox1.SetBounds(trunc(application.display.width/2)-75,trunc(application.display.height/2)-15,150,30);
  Label1.SetBounds(EditBox1.Left, EditBox1.Top - 40, 280,50);
  Button1.SetBounds(EditBox1.Left, EditBox1.Top - 100,180,30);
end;
 
initialization
  Forms.RegisterForm({$I %FILE%}, TForm1);
end.
Link to post
Share on other sites

Thanks for your input.

 

I have already used something similar, but using the QTX message, receive messages through a message subscription class. I don't think Smart Mobile supports mutation event handling. It would be really nice to have a native smart pascal mutationObserver solution to provide developers a way to react to changes in a DOM, something like angular does, it would be as a replacement for mutation events. 

Link to post
Share on other sites
  • Moderators

Understood. I'm sure there are better / more suave ways to deal with this than the above. Something is cooking though, see fb posts in Delphi developer

 

By the way

In retrospect you can do away with all the messaging and make the previous example a lot simpler :

 

procedure TForm1.ObjectReady;
var
  Tag : String;
begin
  inherited;
 
  Tag := EditBox1.Tagid;   // 'OBJ4'
 
  Variant1.a := "initial value of attr a";
  Variant1.b := "initial value of attr b";
 
  asm        //watch for any change of attribute a
    watch(@Variant1, "a", function(){
      window[@Tag].value = @Variant1['a'];
    });
  end;
 
 
  Button1.OnClick := procedure(Sender: TObject)
    begin
    //when changing the objects attribute it's watcher will be invoked
      Variant1['a'] := 'a new object value';
    end;
 
  EditBox1.OnChanged := procedure(Sender: TObject)
    begin
      Variant1['a'] := EditBox1.Text;
      ShowMessage('Object value changed to ' + Variant1['a']);
    end;
 
end;
Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...