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:
-
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.
-
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>
-
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.
-
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>
.
-
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>
-
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.
-
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.
-
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.
-
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.
-
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>