Studio Developer Manual / Version 2304
Table Of Contents
The WidgetType
interface also features the creation of an editor component for
a widget at runtime. Again, if you opt to implement the interface yourself, you have to
provide this functionality from scratch. If you choose your type to extend
ComponentBasedWidgetType
, you simply have to add an editor component, just as
you did for the widget component. Consequently, the TypeScript code for the
SimpleSearchWidgetType
for simple search widgets that are configurable at
runtime looks as follows:
import Config from "@jangaroo/runtime/Config"; import ComponentBasedWidgetType from "@coremedia/studio-client.main.editor-components/sdk/dashboard/ComponentBasedWidgetType"; import SimpleSearchWidget from "@coremedia/studio-client.main.editor-components/sdk/dashboard/widgets/search/SimpleSearchWidget"; import SimpleSearchWidgetEditor from "@coremedia/studio-client.main.editor-components/sdk/dashboard/widgets/search/SimpleSearchWidgetEditor"; //... new ComponentBasedWidgetType({ name: "...", description: "...", iconCls: "...", widgetComponent: Config(SimpleSearchWidget), editorComponent: Config(SimpleSearchWidgetEditor), })
Example 9.77. Simple Search widget Type with Editor Component
Now widgets of this type have their own editor component when a widget on the dashboard is in
edit mode.
However, without further wiring, the changes a user makes in edit mode do not carry over to
the widget component. For the simple search widget it is expected that the user can choose a
search text and content type in edit mode and that the widget shows a corresponding search
result in widget mode. To make this happen, SimpleSearchWidgetEditor
has to
implement the StateHolder
interface. The method
getStateValueExpression()
has to be implemented in a way that the value
expression refers to a simple JavaScript object containing the configuration properties to
be applied to the widget component. Thus, for the simple search widget, these properties are
searchText
and contentType
.
See section Section 9.9, “Storing Preferences” for details of how the state values are persisted and for the limits on the allowed objects.
You could just implement the StateHolder
interface yourself. For convenience,
CoreMedia recommends, that you let your editor component extend StatefulContainer
.
This component inherently implements StateHolder
. It can be configured with a
list of property names along with default values and automatically takes care of building a
state model bean from them. This state model bean is the basis for the
evaluation of the value expression that is returned via
getStateValueExpression()
. Additionally, the bean can be consulted via
getModel()
from subclasses of StatefulContainer
. This can be
utilized for binding the model state to the user interface state. The following listing
exemplifies this for the case of SimpleSearchWidgetEditor
:
import Config from "@jangaroo/runtime/Config"; import ConfigUtils from "@jangaroo/runtime/ConfigUtils"; import TextField from "@jangaroo/ext-ts/form/field/Text"; import ValueExpressionFactory from "@coremedia/studio-client.client-core/data/ValueExpressionFactory"; import ContentTypeNames from "@coremedia/studio-client.cap-rest-client/content/ContentTypeNames"; import BindPropertyPlugin from "@coremedia/studio-client.ext.ui-components/plugins/BindPropertyPlugin"; import VerticalSpacingPlugin from "@coremedia/studio-client.ext.ui-components/plugins/VerticalSpacingPlugin"; import StatefulContainer from "@coremedia/studio-client.ext.ui-components/components/StatefulContainer"; import ContentTypeSelector from "@coremedia/studio-client.ext.cap-base-components/contenttypes/ContentTypeSelector"; class MyWidgetEditor extends StatefulContainer { static override readonly xtype: string = "com.coremedia.cms.widget.config.myWidgetEditor"; constructor(config: Config<StatefulContainer>) { super((() => ConfigUtils.apply(Config(MyWidgetEditor, { properties: "searchText,contentType,preferredSite", items: [ Config(ContentTypeSelector, { fieldLabel: "...", anchor: "100%", itemId: "...", entries: ContentTypeSelector.getAvailableContentTypeEntries(), contentTypeValueExpression: ValueExpressionFactory.create("contentType", this.getModel()), }), Config(TextField, { itemId: "...", anchor: "100%", plugins: [ Config(BindPropertyPlugin, { bindTo: ValueExpressionFactory.create("searchText", this.getModel()), bidirectional: true, }), ], }), ], plugins: [ Config(VerticalSpacingPlugin, {}), ], propertyDefaults: { contentType: ContentTypeNames.DOCUMENT }, }), config))()); } } export default MyWidgetEditor;
Example 9.78. Simple Search Widget Editor Component
This editor component for the simple search widget extends StatefulContainer
and is configured to build a state model for the two properties searchText
and
contentType
. For the content type property, a default is set. The editor
component offers the user a combo box for selecting a content type and a text field for
entering a search text. The user's input is tied to the state model via value expressions
that use getModel()
(inherited from StatefulContainer
) as their
context. This results in keeping the state model updated. Implementing the
StateHolder
interface yourself is not necessary. It is automatically taken care
of by StatefulContainer
on the basis of the always up-to-date state model.
All in all, this results in the simple search widget editor being stateful. When the user switches between widget mode and edit mode for this widget, the editor will keep its state (search text and content type). The state is only lost if the user selects a different widget type in edit mode.
In some cases, it might be useful to not only have the editor of a widget being stateful,
but also the widget itself. This can be realized in the same way shown here for the editor:
by implementing the StateHolder
interface.