0 votes
21 views
ago by (30.6k points)
We need controls that the UI Toolkit does not offer (a signature pad, a map, a rich grid). What is the right structure of a custom coach view so that it behaves like the toolkit controls, is reusable, and survives toolkit upgrades?

1 Answer

0 votes
ago by (30.6k points)

A custom coach view has four parts - layout (HTML template with the content box if it is a container), Behavior (JavaScript handlers), configuration options (typed inputs that coach authors set), and included files (CSS / JS). Structure that has proven maintainable:

<!-- Layout: keep it minimal; give a root element with a stable class and, for containers, a content box -->
<div class="cv-signature">
  <canvas class="cv-signature-pad"></canvas>
  <div class="cv-signature-actions"><button type="button" class="cv-signature-clear">Clear</button></div>
</div>
// Behavior > load: build the widget, wire events, subscribe to binding changes; nothing that needs the element's size
load: function () {
  var self = this, el = this.context.element;
  this._pad = new Packages_free_SignaturePad(el.querySelector(".cv-signature-pad"));            // library from an included JS file
  this._onClear = function () { self._pad.clear(); self.context.binding.set("value", ""); };
  el.querySelector(".cv-signature-clear").addEventListener("click", this._onClear);
  this._pad.onEnd = function () { self.context.binding.set("value", self._pad.toDataURL()); self.context.trigger(); };  // trigger = fire boundary event if configured
  if (this.context.options.readOnly) this._readOnlyHandle = this.context.options.readOnly.bindAll(function (e) { self.setReadOnly(e.newVal); }, this);  // option binding
},
// view: size-dependent work; runs again when the view becomes visible
view: function () { this._pad.resize(this.context.element.clientWidth, 150); if (this.context.binding.get("value")) this._pad.fromDataURL(this.context.binding.get("value")); },
// change: data changed from outside (setData, service result) -> refresh the widget without re-firing our own events
change: function (event) { if (event.type === "binding" && this._pad && event.newVal !== this._pad.toDataURL()) this._pad.fromDataURL(event.newVal || ""); },
// unload: release everything
unload: function () { this.context.element.querySelector(".cv-signature-clear").removeEventListener("click", this._onClear); this._pad.destroy(); this._pad = null; },
// public API for coach authors (this is what ${MyView}.method() calls)
getSignature: function () { return this.context.binding.get("value"); },
setReadOnly: function (ro) { this._pad.readOnly = ro; this.context.element.classList.toggle("is-readonly", !!ro); }
  • Configuration options for everything a coach author might vary (labels, sizes, read-only, colours); read them once in load; options can be bound to variables, so subscribe with bindAll when they may change at runtime.
  • Binding: one business data binding, typed (String, a business object, a list); write through this.context.binding.set so that other views and validation see it; never keep the "real" value only inside the widget.
  • Events: expose behaviour through the view's public methods and coach events (the UI Toolkit style: "On change", "On click" event options that run author-supplied JavaScript); fire a boundary event with this.context.trigger() only if the coach author asks for it (an option), because boundary events leave the coach.
  • Styling isolation: prefix every CSS class (cv-signature-*), scope rules under the root class, never style toolkit classes globally; include CSS as a managed file in the view, not inline in coaches.
  • Composition: for a container control, put a content box in the layout - the framework manages the child views (they load before your load handler), and the parent view can reach them through the context's subview access.
  • Table rows: your view will be instantiated per row - make load cheap and stateless; heavy libraries should be initialised lazily in view.
  • Upgrade safety: depend on the UI Toolkit's documented APIs (setData / getData, events) and on your own view's API; do not reach into the DOM of toolkit controls - their markup changes between versions.

Test the view in a small test coach in the same toolkit with every option combination, read-only mode, inside a table and inside a modal section; that catches most lifecycle bugs before the view is used in ten apps.

References

Related questions

0 votes
1 answer 1.9k views
0 votes
1 answer 1.7k views

723 questions

807 answers

98 comments

4.8k users

Join BPM Community Discord Channel

Welcome to BPM Tips Q&A, Community wiki/forum where you can ask questions and receive answers from other IBM BPM experts and members of the community. Users with 2000 points will automatically be promoted to expert level.
Created by Dosvak LLC
Our Youtube Channel
...