Вопрос

So I've started playing with SMS and I've tried to make a program (label and button) to hit a website with a post request and display the result.

I have no problems with Hints/Warnings/Errors and everything looks good to me. The following code is a rework of a couple of existing examples mashed together.

procedure TForm1.ExecuteCmd;
var
  whttp : TW3HttpRequest;
  wParams : string;
begin
  wHttp := TW3HttpRequest.Create;
  try

    whttp.OnDataReady := lambda (Sender)
      if (w3Label1.caption = '') then
        w3Label1.caption := wHttp.ResponseText;
    end;

    whttp.OnReadyStateChange := lambda (Sender)
      if (wHttp.ReadyState = 4) and (wHttp.Status = 200) then
      begin
        if (w3Label1.caption = '') then
          w3Label1.caption := wHttp.ResponseText;
      end;
    end;

    wParams := 'cmd=TestID1';
    whttp.open('POST','http://www.server1.com/executecmd.php');
    whttp.RequestHeaders['Content-type'] := 'application/x-www-form-urlencoded';
    whttp.Send(wParams);
  finally
    wHttp.free;
  end;
end;

procedure TForm1.W3Button1Click(Sender: TObject);
begin
  ExecuteCmd;
end;

The problem is this, when I actually click the button I get the following error message: Uncaught TypeError: Cannot read property 'readyState' of null [line #6277]

The error is in the auto generated code and seems to have no relation to what I've written specifically. If I take out all references to ReadyState from my code I still get the error.

What am I missing? I feel like it has something to do with the Lambda functions.

Это было полезно?

Решение

Your problem is that you are expecting whttp.Send to block. Send, as its JavaScript equivalent, is asynchronous. Before the POST could even execute, whttp object is freed (in the finally block). When callback (OnReadyStateChanged) is called, whttp was already freed (and is now null) and you are then trying to call ReadyState on that freed (null) object.

Another reason for confusion is that object.Free in Delphi for Windows/OS X destroys the object while in Smart it merely sets the object reference to nil and leaves the destruction to JavaScript's garbage collection. That's why the whttp is still alive after the Free and why the OnReadyStateChanged is called at all.

This works fine:

uses 
  W3System, W3Graphics, W3Components, W3Forms, W3Fonts, W3Borders, W3Application,
  W3Button, W3Inet, W3Memo;

type
  TForm1=class(TW3form)
    procedure W3Button1Click(Sender: TObject);
  private
    {$I 'Form1:intf'}
    whttp: TW3HttpRequest;
  protected
    procedure InitializeForm; override;
    procedure InitializeObject; override;
    procedure Resize; override;
  end;

implementation

{ TForm1}

procedure TForm1.W3Button1Click(Sender: TObject);
var
  wParams: string;
begin
  whttp := TW3HttpRequest.Create;

  whttp.OnReadyStateChange := lambda (Sender)
    if (whttp.ReadyState = 4) and (wHttp.Status = 200) then
    begin
      W3Memo1.Text := wHttp.ResponseText;
      whttp.OnReadyStateChange := nil;
      whttp := nil;
    end;
  end;

  wParams := 'cmd=TestID1';
  whttp.open('POST','http://httpbin.org/post');
  whttp.RequestHeaders['Content-type'] := 'application/x-www-form-urlencoded';
  whttp.Send(wParams);
end;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top