Implementing custom event hyperlinks (drilldown) in the XFRX previewer

XFRX recognizes two types of hyperlinks:

  • “normal” hyperlinks (printed in blue), which navigate to other places in the report or to an external web address (using hyperlinks is described in detail in “Interactive features /Hyperlinks” chapter na stránce 19) and
  • “custom event” hyperlinks (printed in green), where XFRX allows for assigning a custom VFP code that will be called when users click the hyperlink.

This “custom event” hyperlink feature can be used for invoking application specific actions (information forms, custom processes, etc.) or for implementing drill-down functionality – invoking detailed report where the field user clicked on is taken as a parameter for the report (for example, clicking a customer name in the report listing all customers can run a report with detail information about this specific customer). The new report can be directed to a new page of a multipage previewer, which could provide a comfortable environment for “drilling down” specific information – with the ability to go back to the original report without closing the current one, side by side report comparison, exporting / printing selected reports, etc.

The custom event hyperlinks are defined the same way as normal hyperlinks: you add #UR A HREF= to the label or field comment, followed by “vfpev” as a “protocol”, followed by a FoxPro expression to evaluate.

Example: Hello world

#UR A HREF="vfpev:\\messagebox('Hello world')"
If you add this to a field on your report a “Hello world” messagebox pops up whenever you click on that field. 

Please be aware that the text following after HREF= is evaluated during the report execution, at the time the field is about to be rendered. The result is then stored with that particular field and evaluated again when users click on the field. For example, if you need to call your function with a customer ID as a parameter (for example stored in customers.cusID as an integer value), you use something like this:

#UR A HREF="vfpev:\\myfunction("+trans(customers.cusID)+")"

During the report generation the customers.cusID expression is evaluated and the results (e.g. myfunction(1), myfunction(2), etc.) are stored with the individual fields. Myfunction function with the stored parameter is then called when users click on the field.


Enable Custom Hyperlinks for all outputs

XFRX previous versions support custom hyperlinks only in XFRX Preview. But you can change this behavior.

This feature is available since XFRX 18.2.


loSession.SetOtherParams("IncludeCustomHyperlinks",.T.)


Accessing the calling previewer

In case the custom event should result in running a new report, the routine that processes the new report may want to previewer the resulting output in the original previewer, in which the click event occurred. In that case, you can use thisviewer variable as the previewer reference. For example, the following hyperlink definition would be sending the previewer reference as the second parameter of runreport method:

#UR A HREF="vfpev:\\runreport('"+allt(customerid_a)+"',thisviewer)" 

Drilldown solution example

(The following example is available in the DrilldownSample subdirectory of the evaluation as well as commercial package).

The sample solution consists of three reports:

  • A customer index page followed by a brief list of customers. For each customer there is a list of last three orders, total number of orders and the total turnover:
  • When you click on the customer name, a new report with customer details is generated, listing all customer’s orders:
  • By clicking on an order number, an order detail report is generated:


Whenever a new report is generated, it is added as a new page to the previewer container:

 

Here is the full source code:

LPARAMS m.tnReportType, m.tuPar1, m.toViewer
SET PATH TO src; xfrxlib; libs; drilldownsample
 
LOCAL m.loSession, m.lnRetval, m.lcPageCaption, m.loPreview
 
IF EMPTY(m.tnReportType)
   *
   * no report type was sent - we need to initialize the previewer
   * and run the 1st report
   *
   SET CLASSLIB TO xfrxlib
   m.loPreview = CREATEOBJECT("frmMPPreviewer")
   m.tnReportType = 1
   m.toViewer = m.loPreview
ENDIF
 
*
* initialize the XFRX listener
*
m.loSession=EVALUATE([xfrx("XFRX#LISTENER")])
m.lnRetval = loSession.SetParams(,,,,,,"XFF")
IF m.lnRetval = 0
  *
  * now let’s see which report we want to run, select the data
  * and run the report
  *
  DO CASE
     CASE m.tnReportType = 1
          SELECT companyname ;
            FROM customers ;
            ORDER BY companyname INTO CURSOR custindex
 
          REPORT FORM custindex OBJECT m.loSession Nopageeject

          SELECT * ;
            FROM customers INNER JOIN orders ON customers.customerid = orders.customerid ;
                           INNER JOIN orderdetails ON orders.orderid = orderdetails.orderid ;
            ORDER BY customers.companyname, customers.customerid, orderDate Desc, orders.orderid ;
            INTO CURSOR custlist

          REPORT FORM custlist OBJECT m.loSession
          m.lcPageCaption = "Customers list"
 
     CASE m.tnReportType = 2
          SELECT * ;
            FROM customers INNER JOIN orders ON customers.customerid = orders.customerid ;
                           INNER JOIN orderdetails ON orders.orderid = orderdetails.orderid ;
            ORDER BY customers.companyname, customers.customerid, orders.orderid ;
            WHERE customers.customerid = m.tuPar1 ;
            INTO CURSOR custlist

            REPORT FORM custDet OBJECT m.loSession
            m.lcPageCaption = "Customers detail ("+ALLTR(m.tuPar1)+")"
 
     CASE m.tnReportType = 3
          SELECT * ;
            FROM customers INNER JOIN orders ON customers.customerid = orders.customerid ;
                           INNER JOIN orderdetails ON orders.orderid = orderdetails.orderid ;
                           INNER JOIN products ON products.productid = orderdetails.productid ;
            ORDER BY customers.companyname, customers.customerid, orders.orderid ;
            WHERE orders.orderid = m.tuPar1 ;
            INTO CURSOR custlist

          REPORT FORM OrdDet OBJECT m.loSession
          m.lcPageCaption = "Order detail ("+ALLTR(STR(m.tuPar1))+")"
   ENDCASE
ENDIF
 
*
* now preview the report
*
m.toViewer.previewXFF(m.loSession.oxfdocument, m.lcPageCaption)
*
* show the preview if not yet visible
*
IF NOT loPreview.Visible
  *
  * preview in modal Windows
  *
  m.loPreview.Show(1)
EENDIF

As you can see, the code is first called without parameters, which automatically runs the first report (customer list). Then the same code is then called (recursively – as the previewer is in modal mode) from the previewer when users click on the custom event with parameters controlling which report should be run, which parameters should be used for the select statement and what should be the caption of the corresponding page in the previewer.

The report fields’ comments are defined as follows:

Report

Field

Comment

Customer list

Customer name

#UR A HREF="vfpev:\\runreport(2,'"+allt(customerid_a)+"',thisviewer)"

Customer detail

Order number

#UR A HREF="vfpev:\\runreport(3,"+allt(str(orderid_a))+",thisviewer)"