Insert a block for the query

Blocks allow you to share the same query code among multiple widgets without the need to maintain multiple copies of the code.

In Display data in a graphics widget, a copy of the grid widget was used in its entirety to create the graphics widget. Because of that, both widgets contain the exact same query code. To maintain parity, any change you make to one query would need to be made in the other. Instead of maintaining two copies of the same query, you could use a <defblock> element to create a block that contains the Macro Language code for the query and then reference that block in the widgets.

There are two ways you can reference a block in a widget. You could either add an <insert> element between the opening and closing <widget> tags, or you could reference the block via the insert_ attribute to <widget>. The differences will be discussed in the following steps.

To insert a block for the query:

  1. Insert a <defblock> element that contains the query code before the opening <dynamic> tag.
    <defblock name="sales_by_date">
      <link table2="{@product_master}" col="sku" col2="sku" 
       suffix="_prod" type="select">
        <sel value="dept={@selection}"/>
      </link>
      <tabu label="Tabulation on Sales Detail" breaks="{@aggregate_by}">
        <tcol source="xsales" fun="sum" name="tot_sales" 
         label="Sum of`Extended Sales" format="type:currency"/>
      </tabu>
      <sort col="tot_sales" dir="down"/>
      <sel value="({@aggregate_by} <> '')"/>
    </defblock>
    <dynamic selection="19" product_master="pub.doc.retail.product" 
     sales_detail="pub.doc.retail.salesdetail" aggregate_by="groupdesc_prod">
    
      ...
    
    

    The <defblock> is named sales_by_date. This name is used to reference the block.

  2. Delete the query code (which appears below in bold) from both the grid and graphics widgets.
    Note: Do not delete the <graphspec> element from the graphics widget.
    
      ...
    
      <widget class_="grid" base_="{@sales_detail}">
        <link table2="{@product_master}" col="sku" col2="sku" 
         suffix="_prod" type="select">
          <sel value="dept={@selection}"/>
        </link>
        <tabu label="Tabulation on Sales Detail" breaks="{@aggregate_by}">
          <tcol source="xsales" fun="sum" name="tot_sales" 
           label="Sum of`Extended Sales" format="type:currency"/>
        </tabu>
        <sort col="tot_sales" dir="down"/>
        <sel value="({@aggregate_by} <> '')"/>
      </widget>
      <widget class_="graphics" base_="{@sales_detail}" width_="800">
        <link table2="{@product_master}" col="sku" col2="sku" 
         suffix="_prod" type="select">
          <sel value="dept={@selection}"/>
        </link>
        <tabu label="Tabulation on Sales Detail" breaks="{@aggregate_by}">
          <tcol source="xsales" fun="sum" name="tot_sales" 
           label="Sum of`Extended Sales" format="type:currency"/>
        </tabu>
        <sort col="tot_sales" dir="down"/>
        <sel value="({@aggregate_by} <> '')"/>
        <graphspec>
          <chart type="bar">
            <data x="{@aggregate_by}" y="tot_sales"/>
            <ticks xrot="45"/>
            <style xaxissize="10" yaxissize="10"/>
          </chart>
        </graphspec>
      </widget>
    </dynamic>
    
  3. Replace the deleted query code in both the grid and graphics widgets with an <insert> element that references the block.
    
      ...
    
      <widget class_="grid" base_="{@sales_detail}">
        <insert block="sales_by_date"/>
      </widget>
      <widget class_="graphics" base_="{@sales_detail}" width_="800">
        <insert block="sales_by_date"/>
        <graphspec>
          <chart type="bar">
            <data x="{@aggregate_by}" y="tot_sales"/>
            <ticks xrot="45"/>
            <style xaxissize="10" yaxissize="10"/>
          </chart>
        </graphspec>
      </widget>
    </dynamic>
    

    When the QuickApp runs, the Macro Language code from the referenced sales_by_date block is essentially substituted in place of each of the <insert> elements.

    Referencing a block via an <insert> element is advantageous when you have other Macro Language code that you want to execute before the block code runs. You could simply add the additional query code before the <insert> element within the body of the <widget>.

    In addition, using the <insert> element is useful when you want to insert multiple blocks. You would simply add <insert> elements for the blocks in the order you want them to run.

  4. Click Apply.

    Since the code is essentially the same, the results are the same.

Instead of using the <insert> element, you could reference the block code using the insert_ attribute for each <widget>.

  1. Delete the <insert> elements (which appear below in bold) from both the grid and graphics widgets.
    
      ...
    
      <widget class_="grid" base_="{@sales_detail}">
        <insert block="sales_by_date"/>
      </widget>
      <widget class_="graphics" base_="{@sales_detail}" width_="800">
        <insert block="sales_by_date"/>
        <graphspec>
          <chart type="bar">
            <data x="{@aggregate_by}" y="tot_sales"/>
            <ticks xrot="45"/>
            <style xaxissize="10" yaxissize="10"/>
          </chart>
        </graphspec>
      </widget>
    </dynamic>
    
  2. Add an insert_ attribute to both the grid and graphics widgets to reference the block code.
    
      ...
    
      <widget class_="grid" base_="{@sales_detail}" insert_="sales_by_date"/>
      <widget class_="graphics" base_="{@sales_detail}" width_="800"
       insert_="sales_by_date">
        <graphspec>
          <chart type="bar">
            <data x="{@aggregate_by}" y="tot_sales"/>
            <ticks xrot="45"/>
            <style xaxissize="10" yaxissize="10"/>
          </chart>
        </graphspec>
      </widget>
    </dynamic>
    

    When the QuickApp runs, the Macro Language code from the referenced sales_by_date block is essentially inserted before any other Macro Language code in the body of the <widget>. The block code referenced by the insert_ attribute will be executed first.

    Furthermore, you may only specify one block with the insert_ attribute. If you want to insert multiple blocks, you should use multiple <insert> elements (or specify the one you want to run first with the insert_ attribute and the others with multiple <insert> elements in the body of the <widget>).

    Note: In this example, since you are no longer specifying query code directly within the body of the <widget> element for the grid widget, you can use a self-closing <widget> tag. However, since the <graphspec> element still exists within the body of the <widget> element for the graphics widget, you must still use a start tag and end tag for that widget.
  3. Click Apply.

    Since the code is essentially the same, the results are the same.

In this example, the names of the variables in the <defblock> (product_master, selection, and aggregate_by) are the same as the dynamic variables in the QuickApp. Because of that, there is no need to pass any variables to the block when referencing it from either the <insert> element or the insert_ attribute. The block code will essentially be inserted where it is referenced, and each variable in the inserted block code will take the value of the dynamic variable with the same name in the QuickApp.

However, there is no requirement that the variables in the <defblock> have the same name as the dynamic variables in the QuickApp. If the names are different, you would need to pass in the values as parameters. The next few steps will demonstrate how this is done.

  1. Change the names of the variables in the <defblock>.
    For demonstration purposes, the following changes will be made in the <defblock>:
    • product_master will be renamed to prod_table
    • selection will be renamed to department
    • aggregate_by will be renamed to group_by
    <defblock name="sales_by_date" prod_table="" department="" group_by="">
      <link table2="{@prod_table}" col="sku" col2="sku" 
       suffix="_prod" type="select">
        <sel value="dept={@department}"/>
      </link>
      <tabu label="Tabulation on Sales Detail" breaks="{@group_by}">
        <tcol source="xsales" fun="sum" name="tot_sales" 
         label="Sum of`Extended Sales" format="type:currency"/>
      </tabu>
      <sort col="tot_sales" dir="down"/>
      <sel value="({@group_by} <> '')"/>
    </defblock>
    
      ...
    
    
    Note: You must declare the block variables in the opening <defblock> tag. Since you will be passing in the values of these variables when you insert the block, you can set the initial values to the empty string. However, if you wanted to, you could provide initial values. Also, as mentioned earlier, since these are user-defined attributes, they cannot end in an underscore, which differentiates them from the system attributes.
  2. Pass the values of the dynamic variables as parameters to the referenced block.
    
      ...
    
      <widget class_="grid" base_="{@sales_detail}" insert_="sales_by_date"
       prod_table="{@product_master}" department="{@selection}" 
       group_by="{@aggregate_by}"/>
      <widget class_="graphics" base_="{@sales_detail}" width_="800"
       insert_="sales_by_date" prod_table="{@product_master}" 
       department="{@selection}" group_by="{@aggregate_by}">
        <graphspec>
          <chart type="bar">
            <data x="{@aggregate_by}" y="tot_sales"/>
            <ticks xrot="45"/>
            <style xaxissize="10" yaxissize="10"/>
          </chart>
        </graphspec>
      </widget>
    </dynamic>
    

    When referencing a block using the insert_ attribute, you can pass the parameters to the block as attributes in the <widget> tag. Note that the three block variables, prod_table, department, and group_by are added to the <widget> tag for both the grid and graphics widget, and are set to the values of the respective dynamic variables: {@product_master}, {@selection}, and {@aggregate_by}.

    Note: If you were using the <insert> element to reference the block, you would pass the parameters as attributes in the <insert> tag.
  3. Click Apply.

    The results are the same.

Cumulative QuickApp code

The Macro Language code for the QuickApp up to this point is:

<defblock name="sales_by_date" prod_table="" department="" group_by="">
  <link table2="{@prod_table}" col="sku" col2="sku" 
   suffix="_prod" type="select">
    <sel value="dept={@department}"/>
  </link>
  <tabu label="Tabulation on Sales Detail" breaks="{@group_by}">
    <tcol source="xsales" fun="sum" name="tot_sales" 
     label="Sum of`Extended Sales" format="type:currency"/>
  </tabu>
  <sort col="tot_sales" dir="down"/>
  <sel value="({@group_by} <> '')"/>
</defblock>
<dynamic selection="19" product_master="pub.doc.retail.product" 
 sales_detail="pub.doc.retail.salesdetail" aggregate_by="groupdesc_prod">
  <layout background_="lightblue" border_="10">
    <widget class_="dropdown" base_="{@product_master}" 
     inputwidth_="250" value_="@selection" 
     label_="Department:" labelwidth_="75">
      <tabu label="Tabulation on Product Master" breaks="deptdesc">
        <break col="deptdesc" sort="up"/>
        <tcol source="dept" name="dept" fun="first" label="First`Department"/>
      </tabu>
      <colord cols="dept,deptdesc"/>
    </widget>
    <widget class_="dropdown" value_="@aggregate_by" 
     label_="Aggregate by:" labelwidth_="75" inputwidth_="250">
      <table>groupdesc_prod,Group;brand_prod,Brand
      </table>
    </widget>
    <ignore>
      <widget class_="text" text_="Current selection: {@selection}"/>
    </ignore>
  </layout>
  <widget class_="grid" base_="{@sales_detail}" 
   insert_="sales_by_date" prod_table="{@product_master}" 
   department="{@selection}" group_by="{@aggregate_by}"/>
  <widget class_="graphics" base_="{@sales_detail}" width_="800" 
   insert_="sales_by_date" prod_table="{@product_master}" 
   department="{@selection}" group_by="{@aggregate_by}">
    <graphspec>
      <chart type="bar">
        <data x="{@aggregate_by}" y="tot_sales"/>
        <ticks xrot="45"/>
        <style xaxissize="10" yaxissize="10"/>
      </chart>
    </graphspec>
  </widget>
</dynamic>