By default, a QuickApp automatically updates any and all widgets that reference a
dynamic variable whose value has changed. However, this might not be the desired behavior.
QuickApps provide a number of mechanisms to give the user more control.
In Display data in a graphics widget, the grid and graphics widgets
were both updated automatically whenever an item was selected in either of the
drop-down widgets. The queries in these examples are fairly simple, and the data
sets on which they operate are relatively small. However, the cost to run each query
for every widget, in terms of both time and system resources, could become quite
high if the queries were more complex or the data sets were substantially larger. In
this particular example, you might want to allow the user to update the grid and
graphics widgets manually once they are finished making all of their selections.
A widget is invalidated when the data associated with it changes. This can
happen when there is a change to one or more of the dynamic variables that a widget
references. For instance, when the aggregate_by
dynamic variable
changes, both the grid and graphics widgets are invalidated. The default behavior of
a QuickApp is to automatically update any invalidated widgets. However, you can
manually control when widgets are updated by setting the mode_
attribute to manual
in the opening <dynamic>
tag or in the <widget>
tag for a particular widget. If you set
this attribute in the opening <dynamic>
tag, all widgets need to
be manually updated. If you set this attribute in a <widget>
tag, only that particular widget needs to be manually updated. A widget in this
state will remain invalidated until it is told to update.
You can control the behavior of an invalidated widget by setting the
invmode_
attribute for that widget. You can set the
invmode_
to hide
, so that the widget is hidden
until it is updated; to block
, which prevents any interaction with
the widget; or to none
, in which case the widget remains in its
previous state until it is updated.
You can provide the user with a button to manually update invalidated widgets. When
the button is clicked, the invalidated widgets will receive a message to update, and
the widgets will run their associated queries and refresh the data that they are
displaying.
To control when widgets are updated:
-
Set the
mode_
attribute in the opening
<dynamic>
tag to manual
.
...
<dynamic selection="19" product_master="pub.doc.retail.product"
sales_detail="pub.doc.retail.salesdetail" aggregate_by="groupdesc_prod"
mode_="manual">
...
When the mode_
attribute for the
<dynamic>
is set to manual
, any
invalidated widgets remain in that state until manually told to update. By
default, the widgets are blocked and prevented from any interaction until
they receive a message to update. A default message of Please
wait... is presented to the user.
-
In the
<widget>
tag for both the grid and graphics widgets,
set the invmsg_
attribute to a more descriptive message.
...
<widget class_="grid" base_="{@sales_detail}" insert_="sales_by_date"
prod_table="{@product_master}" department="{@selection}"
group_by="{@aggregate_by}"
invmsg_="Click Run for changes to take effect"/>
<widget class_="graphics" base_="{@sales_detail}" width_="800"
insert_="sales_by_date" prod_table="{@product_master}"
department="{@selection}" group_by="{@aggregate_by}"
invmsg_="Click Run for changes to take effect">
<graphspec>
<chart type="bar">
<data x="{@aggregate_by}" y="tot_sales"/>
<ticks xrot="45"/>
<style xaxissize="10" yaxissize="10"/>
</chart>
</graphspec>
</widget>
</dynamic>
-
Click Apply.
The QuickApp will not show any visible changes until the widgets are
invalidated.
-
Select Brand from the Aggregate
by drop-down menu.
Selecting an item from the drop-down menu invalidates both the grid and
graphics widgets, because they both depend on the dynamic variable changed
by the drop-down widget. They are both blocked and display the message
specified by the invmsg_
attribute.
When widgets are in an invalidated state, they must be told when to update.
This can be done by using a button widget with type_="submit"
. When
the button is clicked, it will trigger a refresh of all invalidated
widgets.
-
Add a button widget to update invalidated widgets.
Note: It makes sense to put the new button in the layout containing the
drop-down widgets since it is one of the controls for the state of the
QuickApp.
...
<dynamic selection="19" product_master="pub.doc.retail.product"
sales_detail="pub.doc.retail.salesdetail" aggregate_by="groupdesc_prod"
mode_="manual">
<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>
<widget class_="button" text_="Run" type_="submit"/>
<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}"
invmsg_="Click Run for changes to take effect"/>
...
A <widget>
with class_="button"
has been
added. Because the type_
attribute is set to
submit
, a message will be sent to all invalidated
widgets when this button is clicked.
-
Click Apply.
The Run button is added to the layout under the
drop-down widgets.
-
Select DAIRY DELI from the
Department drop-down menu.
The grid and graphics widgets are invalidated. They are both blocked and
display the specified message.
-
Select Brand from the Aggregate
by drop-down menu.
The grid and graphics widgets remain invalidated and blocked.
-
Click Run.
An update message is sent to the invalidated widgets. The widgets run their
respective queries with the new values of the dynamic variables in the
QuickApp and refresh the data they are displaying.
For certain widgets, you may want their effects to take place immediately.
For instance, you may want to have a checkbox in this QuickApp that controls whether
or not to display the chart; however, you would not want to force the user to click
the Run button upon every interaction with the
checkbox.
-
Add a checkbox to control whether or not the chart is visible.
...
<dynamic selection="19" product_master="pub.doc.retail.product"
sales_detail="pub.doc.retail.salesdetail" aggregate_by="groupdesc_prod"
mode_="manual" display_chart="1">
<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>
<widget class_="checkbox" label_="Display Chart"
value_="@display_chart"/>
<widget class_="button" text_="Run" type_="submit"/>
<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}"
invmsg_="Click Run for changes to take effect"/>
<widget class_="graphics" base_="{@sales_detail}" width_="800"
insert_="sales_by_date" prod_table="{@product_master}"
department="{@selection}" group_by="{@aggregate_by}"
invmsg_="Click Run for changes to take effect"
visible_="{@display_chart}">
<graphspec>
<chart type="bar">
<data x="{@aggregate_by}" y="tot_sales"/>
<ticks xrot="45"/>
<style xaxissize="10" yaxissize="10"/>
</chart>
</graphspec>
</widget>
</dynamic>
A new dynamic variable display_chart
has been added to the
<dynamic>
with an initial value of
1
.
A checkbox widget has been added to the <layout>
, which
will set the value of display_chart
depending on whether or
not the checkbox is selected. (The default behavior for a checkbox widget is
to set the value of the dynamic variable specified by the
value_
attribute to 1
when selected
and 0
when the checkbox is cleared.)
A visible_
attribute, which is set to the value of
display_chart
, has been added to the graphics widget.
Therefore, when display_chart
is set to 1
,
the graphics widget is visible, and when display_chart
is
set to 0
, the graphics widget is hidden.
-
Click Apply.
The Display Chart checkbox is added to the layout
containing the drop-down widgets.
-
Clear the Display Chart checkbox.
Because the graphics widget is dependent on the
display_chart
dynamic variable, and because
mode_
is set to manual
in the opening
<dynamic>
tag, the graphics widget is invalidated
and therefore blocked.
To refresh the widget, you must click the Run button.
However, in this instance, the change to the dynamic variable associated
with the checkbox does not have any effect on the query associated with the
graphics widget. It only dictates whether or not to display the graphics
widget. It would make more sense for the graphics widget to update
automatically.
One of the ways to control when a widget is invalidated is to set the
mode_
in the opening <dynamic>
to
auto
(or just omit it for the default behavior) and to use
the holdfor_
attribute in each <widget>
tag. For a particular widget, the holdfor_
attribute allows you
to specify a list of dynamic variables that, when changed, will invalidate that
widget.
For this example, it would make sense to list the aggregate_by
and selection
dynamic variables in the
holdfor_
attribute for both the grid and graphics widgets
(since their queries depend on those two dynamic variables), but not to include
the display_chart
dynamic variable. That way, when the user
selects an item from either the Aggregate by or
Department drop-down widgets, the grid and graphics
widgets will become invalidated, and the user will need to click
Run to refresh them. However, when the checkbox is
selected or cleared, the graphics widget will be displayed or hidden
automatically.
-
Change the
update_
attribute to auto
in the
opening <dynamic>
tag, and set the holdfor_
attribute for the grid and graphics widget to the aggregate_by
and selection
dynamic variables.
...
<dynamic selection="19" product_master="pub.doc.retail.product"
sales_detail="pub.doc.retail.salesdetail" aggregate_by="groupdesc_prod"
mode_="auto" display_chart="1">
...
<widget class_="grid" base_="{@sales_detail}" insert_="sales_by_date"
prod_table="{@product_master}" department="{@selection}"
group_by="{@aggregate_by}"
invmsg_="Click Run for changes to take effect"
holdfor_="@aggregate_by,@selection"/>
<widget class_="graphics" base_="{@sales_detail}" width_="800"
insert_="sales_by_date" prod_table="{@product_master}"
department="{@selection}" group_by="{@aggregate_by}"
invmsg_="Click Run for changes to take effect"
visible_="{@display_chart}" holdfor_="@aggregate_by,@selection">
<graphspec>
<chart type="bar">
<data x="{@aggregate_by}" y="tot_sales"/>
<ticks xrot="45"/>
<style xaxissize="10" yaxissize="10"/>
</chart>
</graphspec>
</widget>
</dynamic>
Note: Instead of setting the mode_
attribute to
auto
in the opening <dynamic>
tag, you could omit the mode_
attribute entirely since
the default behavior for the QuickApp is to automatically update all
invalidated widgets.
-
Click Apply.
-
Clear the Display Chart checkbox.
The chart is hidden.
-
Select the Display Chart checkbox.
The chart is displayed.
-
Select Brand from the Aggregate
by drop-down menu.
The grid and graphics widget are both invalidated and blocked.
-
Select DAIRY DELI from the
Department drop-down menu.
The grid and graphics widget remain invalidated and blocked.
-
Click Run.
The grid and graphics widgets are updated to reflect the new values for the
aggregate_by
and selection
dynamic
variables.
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"
mode_="auto" display_chart="1">
<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>
<widget class_="checkbox" label_="Display Chart"
value_="@display_chart"/>
<widget class_="button" text_="Run" type_="submit"/>
<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}"
invmsg_="Click Run for changes to take effect"
holdfor_="@aggregate_by,@selection"/>
<widget class_="graphics" base_="{@sales_detail}" width_="800"
insert_="sales_by_date" prod_table="{@product_master}"
department="{@selection}" group_by="{@aggregate_by}"
invmsg_="Click Run for changes to take effect"
visible_="{@display_chart}" holdfor_="@aggregate_by,@selection">
<graphspec>
<chart type="bar">
<data x="{@aggregate_by}" y="tot_sales"/>
<ticks xrot="45"/>
<style xaxissize="10" yaxissize="10"/>
</chart>
</graphspec>
</widget>
</dynamic>