Kogito Tooling Examples —How to create a more complex custom View

Protograph by Taylor Rees

This is part of a series of blog posts, and this one covers “How to create a more complex custom View”.

You can navigate through the series by clicking on the following topics:


This section will cover a new View example called “Ping Pong View”, but now it will feature a factory. This change will make it more flexible to use other frameworks than React or no framework at all. You can check out all the code of this section here. A big part of the code is pretty similar to the ‘To-do’ List View, so this part is not going to be covered here.

A PingPongView is a component that can send “Pings” to the Channel and also receive ”Ping” and “Pong” notifications from the Channel. The main idea is that a PingPongView instance doesn’t know whether there are more than one PingPongViews on the screen, since it only communicates with the Channel.

As said before, the Ping Pong View’s main difference is the usage of a custom factory to create its Views. Our factory is a simple interface with a create method that returns a PingPongView.

import { MessageBusClientApi } from "@kogito-tooling/envelope-bus/dist/api";
import { PingPongChannelApi, PingPongInitArgs } from "../api";
export interface PingPongFactory {
create(initArgs: PingPongInitArgs, channelApi: MessageBusClientApi<PingPongChannelApi>): PingPong;

A PingPongView has a reactComponent optional method, which should return a React component.

import { PingPongApi } from "../api";
export interface PingPong extends PingPongApi {
reactComponent?(): React.ReactNode;
view raw PingPong.ts hosted with ❤ by GitHub

The PingPongEnvelopeView is identical to the TodoListEnvelopeView except for the factory passed as argument on the init method and on the PingPongEnvelopeApiImpl instancialization.

import { EnvelopeBus } from "@kogito-tooling/envelope-bus/dist/api";
import { Envelope } from "@kogito-tooling/envelope";
import { PingPongChannelApi, PingPongEnvelopeApi } from "../api";
// …
export function init(args: { container: HTMLElement; bus: EnvelopeBus; pingPongViewFactory: PingPongFactory }) {
const envelope = new Envelope<
const envelopeViewDelegate = async () => {
const ref = React.createRef<PingPongEnvelopeViewApi>();
return new Promise<() => PingPongEnvelopeViewApi>((res) =>
ReactDOM.render(<PingPongEnvelopeView ref={ref} />, args.container, () => res(() => ref.current!))
const context: PingPongEnvelopeContext = {};
return envelope.start(envelopeViewDelegate, context, {
create: (apiFactoryArgs) => new PingPongEnvelopeApiImpl(apiFactoryArgs, args.pingPongViewFactory),

Our Ping Pong View API implementation (PingPongEnvelopeApiImpl) uses the PingPongFactory on its init method as well.

import { EnvelopeApiFactoryArgs } from "@kogito-tooling/envelope";
import { Association, PingPongChannelApi, PingPongEnvelopeApi, PingPongInitArgs } from "../api";
// …
export class PingPongEnvelopeApiImpl implements PingPongEnvelopeApi {
private readonly args: EnvelopeApiFactoryArgs<
private readonly pingPongViewFactory: PingPongFactory
) {}
public async pingPongView__init(association: Association, initArgs: PingPongInitArgs) {
this.args.envelopeBusController.associate(association.origin, association.envelopeServerId);
const pingPong = this.pingPongViewFactory.create(initArgs, this.args.envelopeBusController.manager.clientApi);
await this.args.view().setView(pingPong)

Last but not least, the View implementation uses the reactComponent method to render the View content. In case the reactComponent wasn’t implemented (not using the React framework), the content to be rendered can be simply attached to the div using the id.

export interface PingPongEnvelopeViewApi {
setView(page: PingPong): Promise<void>;
export const PingPongEnvelopeView = React.forwardRef((props, forwardedRef) => {
const [view, setView] = useState<PingPong>();
useImperativeHandle(forwardedRef, () => ({ setView: setView }), []);
return (
<div className={"ping-pong-view–main"}>
{view && (
<h2>This is an implementation of Ping-Pong View</h2>
<p className={"ping-pong-view–p-iframe"}> The {"<iframe>"} border is green </p>
<p className={"ping-pong-view–p-ping-pong"}> The Ping-Pong View implementation border is red </p>
<div id={"ping-pong-view-container"} className={"ping-pong-view-container"}>

React Implementation

We’ve prepared a React implementation of the Ping Pong View, and this is how it looks like.

The red border can be implemented utilizing any tool you want!

In this implementation, we create a factory that implements the PingPongFactory, which simply returns an object with the reactComponent method. Remember, if we’ve implemented this factory using another framework, or no framework at all, we’d have manually added the PingPongView implementation on the specific div or utilizing any other option available.

import { MessageBusClientApi } from "@kogito-tooling/envelope-bus/dist/api";
// …
export class PingPongReactImplFactory implements PingPongFactory {
public create(initArgs: PingPongInitArgs, channelApi: MessageBusClientApi<PingPongChannelApi>) {
const ref = React.createRef<PingPongApi>();
const pingPongView: PingPong = {
reactComponent: () => <PingPongReactImpl initArgs={initArgs} channelApi={channelApi} ref={ref} />,
return pingPongView;

A PingPongReactImpl is a React component that implements the PingPongApi. You can check its code here.

Wrapping up

Hopefully, after this example, you know what you need to do to create a View utilizing another framework! In the next and last section, we’re going to wrap up all the Kogito Tooling Examples in how to create a Web App, which will contain all our available Editors (Base64Png, BPMN and DMN) and our custom Views (“To-do” List and “Ping Pong”).

Thanks for reading, and see you there!


This post was original published on here.
0 0 votes
Article Rating
Notify of
Inline Feedbacks
View all comments