Quantcast
Channel: SAPUI5 Developer Center
Viewing all articles
Browse latest Browse all 789

How to: temporary PDF creation and download

$
0
0

     This blog post describes how to create a PDF document based on input from the UI5 front-end and return a (temporary) download link to the user. It is mostly a collection of things I discovered whilst handling a task which involved exactly this king of thing.

 

1. Building the .pdf


     There are several ways to build the pdf itself. The easiest that I could find was using smartforms (you can find more details on how to create and use smartforms in the link). One thing to note is that the smart form has an interface similar with that of  a function module, i.e. you can pass data (values, structures, tables, basically anything) to it in order to fill the placeholders, generate tables, etc. Once you have created your  "template" using the smartforms feature you should create a function module / static method which uses this smart form, converts it into pdf format (because smart forms are not directly translated into .pdf files when executed) and saves it on the application server.


  • Getting the raw (otf) format output of the smart-form:

 

 

  DATA:

    ls_job_output_info      TYPE ssfcrescl,

    ls_document_output_info TYPE ssfcrespd,

    ls_job_output_options   TYPE ssfcresop,

    ls_output_options       TYPE ssfcompop,

    ls_control_parameters   TYPE ssfctrlop,

    lv_fm_name              TYPE rs38l_fnam.

 

 

  CONSTANTS c_formname TYPE tdsfname VALUE'<<smart form name>>'.

  CONSTANTS c_filename TYPE string VALUE'<<filename>>.pdf'.

 

  CALLFUNCTION'SSF_GET_DEVICE_TYPE'

    EXPORTING

      i_language   = sy-langu

      i_application = 'SAPDEFAULT'

    IMPORTING

      e_devtype    = ls_output_options-tdprinter.

 

  ls_control_parameters-no_dialog = 'X'.

  ls_control_parameters-getotf = 'X'.

 

  CALLFUNCTION'SSF_FUNCTION_MODULE_NAME'

    EXPORTING

      formname = c_formname

    IMPORTING

      fm_name = lv_fm_name.

 

  CALLFUNCTION lv_fm_name

    EXPORTING

      control_parameters  = ls_control_parameters

      output_options      = ls_output_options

      "add your custom smart form parameters here

    IMPORTING

      document_output_info = ls_document_output_info

      job_output_info     = ls_job_output_info

      job_output_options  = ls_job_output_options.

 

 

 

  • Converting the otf to pdf format:

 

 

  DATA: lt_lines           TYPESTANDARDTABLEOF tline,

        lv_pdf_content     TYPE                   xstring.

 

  CALLFUNCTION'CONVERT_OTF'

    EXPORTING

      format  = 'PDF'

    IMPORTING

      bin_file = lv_pdf_content

    TABLES

      otf     = ls_job_output_info-otfdata

      lines   = lt_lines

    EXCEPTIONS

      OTHERS  = 1.

 

 

 

  • You can either save the .pdf temporarily or you can persistently save the xstring value (returned in lv_pdf_content) in a database table and build a GW function import / entity which provides the binary content as a property. We will explore the first version. The first version has the advantage that it does not store large amounts of data in the database, although it will have to recreate the .pdf each time the user may want to download it (this is generally a good solution, as users mostly download receipts/confirmations/other pdf stuff just one time).

 

 

  DATA:   lr_cached_response TYPEREFTO            if_http_response,

          lv_header_text     TYPE                   string,

          lt_lines           TYPESTANDARDTABLEOF tline.

 

  CONSTANTS: c_path TYPE string VALUE`<<desired url local path>>` ,

             c_exp  TYPE i VALUE360."<<how long (secs) should the pdf be 'stored'>>

 

 

  CREATEOBJECT lr_cached_response TYPE cl_http_response EXPORTING add_c_msg = 1.

 

  lr_cached_response->set_header_field(

              name = if_http_header_fields=>content_type

              value = 'application/pdf').

 

***optional_start*** "should only be used if you wish to force a download

                     "(some browsers open .pdf files in tabs if you don't use it)

 

  CONCATENATE`attachment; filename="` c_filename `"` INTO lv_header_text.

 

  lr_cached_response->set_header_field(

              name = if_http_header_fields=>content_disposition

              value = lv_header_text ).

 

***optional_end***

 

  lr_cached_response->set_status(code = 200 reason = 'OK').

  lr_cached_response->server_cache_expire_rel( expires_rel = c_exp ).

 

*you can get the server base url using: cl_http_server=>get_location( ).

*when you build your path.

 

  lr_cached_response->set_data( lv_pdf_content ).

  cl_http_server=>server_cache_upload( url     = c_path

                                       response = lr_cached_response

                                       scope   = ihttp_inv_global ).

 

  • You have your .pdf saved at the url given in c_path (you may want to replace this constant with a url created at run-time, e.g. with a guid appended to the server base url.

 

2. Using it in GW

    

     Let's link the pdf creation function module / static method to the gateway service. I suggest using a function import which receives parameters derived from the structure(s) used in the smart form interface and returns a complex type which contains the URL (and other metadata if necessary). If appropriate, you can also create an entity set or use an existing entity and pass the URL as a property.

     Gateway service 'nodes':

     Function import settings:


     After you generate the run-time artifacts, you must redefine the method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~EXECUTE_ACTION of the _DPC_EXT class and call your PDF creation function module (after you have checked that your function import is requested and not some other one). More on function imports here.


3. Linking it to the UI


     The gateway function import must communicate with the UI5 app. To call the function import use the callFunction method of your oDataModel object. You must write a javascript function to handle the success event (check out the parameters of the above-mentioned function). The function should be something like this:


function(oData, response)
{      var pdfURL = oData['getPdfFile'].url;     //use the url however you want.
}


     You have multiple ways to display the PDF once you have the URL. One thing that I have done, is to check if the PDF file still exists before redirecting the user to download it (the PDF may have expired if the user took a long time between creating the PDF and trying to download it; if this is the case and he presses the download link, a 404 Not Found default file will be opened and the UI5 context will be destroyed). You can use the following snippet to check if the pdf exists:

jQuery.ajax({    type: 'HEAD',    url: pdfURL,    success: function() {            //this will make the browser download the pdf            window.location.href=pdfURL;      },     error: function(){ /* error handling */ }
});

   

     If you want to display the .pdf file, here are some thoughts (you must not include the optional part in the PDF creation code):

  • Directly open it using  window.location.href=pdfURL; but this will basically exit from your application
  • Use the window.open function to open a new tab / browser window
  • Open it in an iframe (you can include the iframe in a UI5 dialog, or any other UI5 container control):
new sap.ui.core.HTML( {content: "<iframe style=\"width:100%;height:100%\" src=\"" + pdfURL+ "\">Not supported</iframe>"} )
  • All the above methods assume that the browser can display PDF files. If your PDF is accessible via a public URL (not on intranet and not behind a login), you can also use the Google Documents API. You can combine this method with all of the above. To use the API, you just have to build this URL:
var googleURL = "http://docs.google.com/viewer?url=" + pdfURL + "&embedded=true"

          and use it instead of the regular PDF URL.


Viewing all articles
Browse latest Browse all 789

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>