== Rendering Widgets include::../variables.adoc[] === WidgetRenderer classes In general, to fully implement a Widget, you must define its `QWidgetMetaData`, and supply a subclass of `AbstractWidgetRenderer`, to provide the data to the widget. (Note the "No Code" category of widgets, which are an exception to this generalization). The only method required in a subclass of `AbstractWidgetRenderer` is: public RenderWidgetOutput render(RenderWidgetInput input) throws QException The fields available in `RenderWidgetInput` are: - `Map queryParams` - These are parameters supplied by the frontend, for example, if a user selected values from dropdowns to control a dimension of your widget, those name/value pairs would be in this map. Similarly, if your widget is being included on a record view screen, then the record's primary key will be in this map. - `QWidgetMetaDataInterface widgetMetaData` - This is the meta-data for the widget being rendered. This can be useful in case you are using the same renderer class for multiple widgets. The only field in `RenderWidgetOutput` is: - `QWidgetData widgetData` - This is a base class, with several attributes, and more importantly, several subclasses, specific to the type of widget that is being rendered. ==== Widget-Type Specific Rendering Details Different widget types expect & require different types of values to be set in the `RenderWidgetOutput` by their renderers. ===== Pie Chart The `WidgetType.PIE_CHART` requires an object of type `ChartData`. The fields on this type are: * `chartData` an instance of `ChartData.Data`, which has the following fields: ** `labels` - *List, required* - the labels for the slices of the pie. ** `datasets` - *List required* - the data for each slice of the pie. For a Pie chart, only a single entry in this list is used (other chart types using `ChartData` may support more than 1 entry in this list). Fields in this object are: *** `label` - *String, required* - a label to describe the dataset as a whole. e.g., "Orders" for a pie showing orders of different statuses. *** `data` - *List, required* - the data points for each slice of the pie. *** `color` - *String* - HTML color for the slice *** `urls` - *List* - Optional URLs for slices of the pie to link to when clicked. *** `backgroundColors` - *List* - Optional HTML color codes for each slice of the pie. [source,java] .Pie chart widget example ---- // meta data new QWidgetMetaData() .withName("pieChartExample") .withType(WidgetType.PIE_CHART.getType()) .withGridColumns(4) .withIsCard(true) .withLabel("Pie Chart Example") .withCodeReference(new QCodeReference(PieChartExampleRenderer.class)); // renderer private List labels = new ArrayList<>(); private List colors = new ArrayList<>(); private List data = new ArrayList<>(); /******************************************************************************* ** helper method - to add values for a slice to the lists *******************************************************************************/ private void addSlice(String label, String color, Number datum) { labels.add(label); colors.add(color); data.add(datum); } /******************************************************************************* ** main method of the widget renderer *******************************************************************************/ @Override public RenderWidgetOutput render(RenderWidgetInput input) throws QException { addSlice("Apple", "#FF0000", 100); addSlice("Orange", "#FF8000", 150); addSlice("Banana", "#FFFF00", 75); addSlice("Lime", "#00FF00", 100); addSlice("Blueberry", "#0000FF", 200); ChartData chartData = new ChartData() .withChartData(new ChartData.Data() .withLabels(labels) .withDatasets(List.of( new ChartData.Data.Dataset() .withLabel("Flavor") .withData(data) .withBackgroundColors(colors) .withUrls(urls)))); return (new RenderWidgetOutput(chartData)); } ---- ===== Bar Chart #todo# ===== Stacked Bar Chart #todo# ===== Horizontal Bar Chart #todo# ===== Child Record List #todo# ===== Line Chart #todo# ===== Small Line Chart #todo# ===== Statistics #todo# ===== Parent Widget #todo# ===== Composite A `WidgetType.COMPOSITE` is built by using one or more smaller elements, known as `Blocks`. Note that `Blocks` can also be used in the data of some other widget types (specifically, within a cell of a Table-type widget, or (in the future?) as a header above a pie or bar chart). A composite widget renderer must return data of type `CompositeWidgetData`, which has the following fields: * `blocks` - *List, required* - The blocks (1 or more) being composited together to make the widget. See below for details on the specific Block types. * `styleOverrides` - *Map* - Optional map of CSS attributes (named following javascriptStyleCamelCase) to apply to the `
` element that wraps the rendered blocks. * `layout` - *Layout enum* - Optional specifier for how the blocks should be laid out. e.g., predefined sets of CSS attributes to achieve specific layouts. ** Note that some blocks are designed to work within composites with specific layouts. Look for matching names, such as `Layout.BADGES_WRAPPER` to go with `NumberIconBadgeBlock`. [source,java] .Composite widget example - consisting of 3 Progress Bar Blocks, and one Divider Block ---- // meta data new QWidgetMetaData() .withName("compositeExample") .withType(WidgetType.COMPOSITE.getType()) .withGridColumns(4) .withIsCard(true) .withLabel("Composite Example") .withCodeReference(new QCodeReference(CompositeExampleRenderer.class)); // renderer public RenderWidgetOutput render(RenderWidgetInput input) throws QException { CompositeWidgetData data = new CompositeWidgetData(); data.addBlock(new ProgressBarBlockData() .withValues(new ProgressBarValues() .withHeading("Blocks") .withPercent(new BigDecimal("78.5")))); data.addBlock(new ProgressBarBlockData() .withValues(new ProgressBarValues() .withHeading("Progress") .withPercent(new BigDecimal(0)))); data.addBlock(new DividerBlockData()); data.addBlock(new ProgressBarBlockData() .withStyles(new ProgressBarStyles().withBarColor("#C0C000")) .withValues(new ProgressBarValues() .withHeading("Custom Color") .withPercent(new BigDecimal("75.3")))); return (new RenderWidgetOutput(data)); } ---- ===== Table #todo# ===== HTML #todo# ===== Divider #todo# ===== Process #todo# ===== Stepper #todo# ===== Data Bag Viewer #todo# ===== Script Viewer #todo# === Block-type Specific Rendering Details For Composite-type widgets (or other widgets which can include blocks), there are specific data classes required to be returned by the widget renderer. Each block type defines a subclass of `AbstractBlockWidgetData`, which is a generic class with 3 type parameters: * `V` - an implementation of `BlockValuesInterface` - to define the type of values that the block uses. * `S` - an implementation of `BlockSlotsInterface` (expected to be an `enum`) - to define the "slots" in the block, that can have Tooltips and/or Links applied to them. * `SX` - an implementation of `BlockStylesInterface` - to define the types of style customizations that the block supports. These type parameters are designed to ensure type-safety for the application developer, to ensure that only === Additional Tips * To make a Dashboard page (e.g., an App consisting of Widgets) with a parent widget use the parent widget's label as the page's label: ** On the `QAppMetaData` that contains the Parent widget, call `.withSupplementalMetaData(new MaterialDashboardAppMetaData().withShowAppLabelOnHomeScreen(false))`. ** In the Parent widget's renderer, on the `ParentWidgetData`, call `setLabel("My Label")` and `setIsLabelPageTitle(true)`.