Delphi IntraWeb TIWFileUploader client side management

381 Views Asked by At

Delphi IntraWeb has a component to manage file upload in async way. I would like to:

  • Allow browser user to select a file;
  • Test the file name client side (i.e. in order to verify some condition or info and ask user for supplementary info depending from selected file name). The JS procedure should be in charge to provide formatted info about the file name; the provided default info span is too small and I want to use different interface items (cards and classes), and the file name displayed is shortened;
  • Execute upload: the "Upload" button will be shown only conditionally, controlled client side.

Looking to FileUploaderDemo.prj I found there are some useful client side script procedures from IntraWeb:

IW.FileUploader("IWFILEUPLOADER5").selectFile(); 
IW.FileUploader("IWFILEUPLOADER5").startUpload();

So I can control the selection and the upload processes client side as needed, but I need to fire my own event handler on selected file, and process file info.

I guess if others IntraWeb JS client side procedures are available, similar to:

*** EXAMPLE ***    
IW.FileUploader("IWFILEUPLOADER5").selectedFileName(); // get the selected file name
IW.FileUploader("IWFILEUPLOADER5").selectedFileSize(); // get the selected file size
IW.FileUploader("IWFILEUPLOADER5").hideDefaultInfoPanel(); // hide the default info panel

And if a JS event exists in order to fire my own JS procedure when users select a file.

EDIT 28 jan 2023

After many attempts I found this solution valid for may goal, but still not THE solution: I would like to process the file name client side only, without sending info's to the server. Anyway I can process it server side.

Drop a TIWFileUploader into the TIWForm, disable AutoUpload property. Drop a select button and an upload button like these:

  object btnSelect: TIWButton
    Left = 257
    Top = 155
    Width = 121
    Height = 25
    Caption = 'Select File'
    Color = clBtnFace
    Font.Color = clNone
    Font.Size = 10
    Font.Style = []
    FriendlyName = 'Select File'
    ScriptEvents = <
      item
        EventCode.Strings = (
          'IW.FileUploader("EUPLOADTT").selectFile();')
        Event = 'onClick'
      end>
    TabOrder = 2
  end
  object btnUpload: TIWButton
    Left = 257
    Top = 190
    Width = 121
    Height = 25
    Caption = 'Upload File'
    Color = clBtnFace
    Font.Color = clNone
    Font.Size = 10
    Font.Style = []
    FriendlyName = 'IWButton1'
    ScriptEvents = <
      item
        EventCode.Strings = (
          'IW.FileUploader("EUPLOADTT").startUpload();')
        Event = 'onClick'
      end>
    TabOrder = 3
  end

Render "btnUpload" hidden, so the user do now see it (i.e. add class "d-none", "hidden", or any other supported client side to the IW tag).

Assign the server side event handler OnAsyncSelectFile similar to this:

procedure TfHome.eUploadTTAsyncSelectFile(Sender: TObject;
  EventParams: TStringList);
begin
  ttUploader.Init(EventParams.Values['FileName']);
  ttUploader.Parse();
  var j := ttUploader.AsJSon;
  WebApplication.CallBackResponse.AddJavaScriptToExecuteAsCDATA(Format('uplCheck(%s);',[j.ToString]));
  j.Free;
end;

This is fired after user selected a file (or dropped it into the upload area - not perfect IW behavior here, but it works)
The ttUploader object is mine: here I process the file name and return a JSON object containing info so the client side can show a customized form asking user to confirm upload. In my original question I said I have to check client side only the file name, but real implementation required I have to check database in order to find what action I have di ask to the user (i.e.: create ticket; update ticket; etc...). So this workaround is perfect form my actual needs.

Client side uplCheck(info) function shows the form to the user, including an action button. Bind to action button to this event:

function uplOk() {
  executeAjaxEvent("&clkMode="+ttMode, null, "TT.uplProc",false,null,false);
  $("#uplForm").modal("hide");
}

The ttMode var contains the kind of action returned by the server after file name parsing (i.e.: create a ticket).

The executeAjaxEvent calls the registered callback IW function:

procedure TfHome.IWAppFormCreate(Sender: TObject);
begin
  ...
  WebApplication.RegisterCallBack('TT.uplProc', uplProc);
  ...
end;

Server side:

procedure TfHome.uplProc(EventParams: TStringList);
begin
  ttUploader.actionAfterLoad := EventParams.Values['clkMode'];
  WebApplication.CallBackResponse.AddJavaScriptToExecuteAsCDATA(Format('uplOkPost();',[]));
end;

The server save the action required, then call uplOkPost() JS function client side:

function uplOkPost() {
  $("#BTNUPLOAD").addClass("disabled").trigger("click");
}

Looking at my code just now, I thin I can call directly IW.FileUploader("EUPLOADTT").startUpload(); without having to call the click handler of the button, but I never tried it.

Calling this JS function, the file is loaded client side, and I saved before the action type to be performed on eUploadTTAsyncUploadSuccess event handler. Here, I assigned SaveFile := false; in order to manage the file as a stream:

function fileUpload(): string;
  begin
    Result := 'S';
    var s := TMemoryStream.Create;
    try
      try
        eUploadTT.SaveToStream(FileName, s);
        var o := TJSONObject.Create;
        //s.LoadFromFile(ttUploader.DownloadedFullFileName);
        o.AddPair('fileData',EncodeBase64(s.Memory,s.Size));
        o.AddPair('rootFileName',ttUploader.RootFileName);
        o.AddPair('ttCod',ttUploader.codTT);
        o.AddPair('ttStato',ttUploader.stato);
        o.AddPair('ttAnno',TJSONNumber.Create(ttUploader.annoTT));
        o := UserSession.ClkPadFileBrowse.PutTTData(o);
      except on E: Exception do begin
        Result := 'E';
        ttUploader.lastError := Format('Error loading file - "%s"',[E.Message]);
      end;
      end;
    finally
      // Release the stream
      s.Free;
    end;
  end;

I assigned eUploadTTAsyncUploadError, eUploadTTAsyncUploadSuccess in order to manage exception and work flow (user feedback).

0

There are 0 best solutions below