Skip to content

CodeCoupler UI Widget

Overview

A widget is a class derived from the CodeCoupler base class Widget. A widget will be initialized within any container element. The content of the container can be freely defined.

Start a Widget

You cannot initialize a Widget class directly. A widget can be started over the widget factory method widget(appStart) which is available in all components.

1
this.widget(widgetStart);

Error Handling

If any error occurs the initializing process will stop and an error will be thrown. The widget will be blocked with a message.

The error message can be modified in the system wide setting messages.WIDGET.ERROR_INIT.

In case that the error occurs during the system initialization, the parent system will catch the and handle this error. Please read the chapter "Error Handling" in the documentation of System for furher informations.

Start Definition Object

The widget start definition object widgettart is not optional. It have to be an object and can have the following properties:

container [ String | HTMLElement | jQuery Object ] (Default: Current Stage)

This is the container where the widget structure will be build. The container itself will be not touched. All additional elements will be created inside of this container.

id [ String ] (Default: Random String)

An unique id that represents the widget instance. You cannot create two widgets with the same id on the same parent instance. If you do not specify an id a random id will be used. You should always use an id if you need to access the widget instance over the property widgets which is avaliable in all parent instances.

type [ String ] (Default: "widget")

Can be widget, vue, vue-sr or vue-mr. It specify the type of the widget class which can be a plain JavaScript Widget class or a Vue application.

widget [ Class | Vue ] (Mandatory)

The widget class or widget vue application to instantiate.

options [ Object ] (Default: undefined)

Options which should be passed on to the widget.

settings [ Object ] (Default: undefined)

Override here the system wide settings for this widget and all child components.

► Read more about system wide settings

on [ Object ] (Default: undefined)

Early bind callbacks to events. In some cases the application fires events within the initialization phase. Instead of using instance.on("eventname",callback) after initialization (what would be too late) you can define here callbacks which will be early binded to be able to react to this events.

Define just an object with the eventnames as properties and callback functions as values:

1
2
3
on: {
  eventname: callback
}

Implement a Widget

Basics

You can write a new widget as plain JavaScript class or as a Vue application.

To write a new widget class you have to extend the CodeCoupler class Widget:

1
2
3
4
5
6
import { Widget } from "@codecoupler/cc-ui";
export default class extends Widget {
  async init() {
    //Init process here
  }
}

The only method you have to provide is async init().

To write a Vue based widget, just write an Vue application which receives the following props:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<template>
  <!-- Put your Template here -->
</template>
<script>
export default {
  props: {
    component: { type: Object, default: null },
  },
};
</script>
<style lang="postcss" scoped>
/* Put your Stylesheet here */
</style>

The property component is a pointer to a base instance of a Widget class. From there you can access all methods and properties of a component like you were writing a plain JavaScript class and would access over this.

Initialization and Starting Process

flowchart TB

  subgraph S1 [ ]
    S1A[Init Container<br>See 'DOM Layout'] --> S1C
    S1C[Block Widget]
  end

  S1C --> A
  A[Execute `init` Method] --> S2A
  style A color:#000,fill:#ffc929,stroke:#333,stroke-width:4px

  subgraph S2 [ ]
    S2A[Unblock Widget]
  end

  S2A --> I
  I[Widget is initialized]

DOM Layout

After starting a widget the container element itself will not be touched. Instead, one or two more elements are created within the container. By default two elements will be created. The first one will provide a custom scroller and the second is just a plain div. This inner div is the element which can be used to implement the widget interface.

The container of your new widget will be blocked until the initialization finishes.

The scroll functionality guarantees the widget to use the entire width and height of the inner div and the container to keep its dimensions. This is a basic principle that should be retained: the container defines the dimensions.

Default Structure:

┌──────────────────────────────────────────────────────────────────────────┐
│  This is the container defined in the widgetStart argument.              │
│  Accessible over this.env.container or this.env.$container               │
│                                                                          │
│  isolation: isolate                                                      │
│  ┌────────────────────────────────────────────────────────────────────┐  │
│  │ div.cc-widget-container                                            │  │
│  │ Container in where the PerfectScrollbar will be initialized.       │  │
│  │ Accessible over this.env.scroll or this.env.$scroll                │  │
│  │                                                                    │  │
│  │ height: 100%;                                                      │  │
│  │ width: 100%;                                                       │  │
│  │ position: relative;                                                │  │
│  │ overflow: hidden;                                                  │  │
│  │  ┌──────────────────────────────────────────────────────────────┐  │  │
│  │  │ div                                                          │  │  │
│  │  │ Here is the place where the widget will be initialized.      │  │  │
│  │  │ Accessible over this.env.element or this.env.$element        │  │  │
│  │  │                                                              │  │  │
│  │  │ min-height: 100%;                                            │  │  │
│  │  │ min-width: 100%;                                             │  │  │
│  │  └──────────────────────────────────────────────────────────────┘  │  │
│  └────────────────────────────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────────────────────────────┘

The property this.env contains the properties container, scroll and element to access the single elements. The properties $container, $scroll and $element are the jQuery counterparts. Normally you should not manipulate the container and the scroll element. The scroll element can be used to scroll your widget. You can use here plain JavaScript DOM methods scrollTop and scrollLeft.

If the scroll container is actually not needed, the widget can announce this via overriding the prepare method (read below). In this case the inner div will get the style overflow: "hidden"; height: "100%"; width: "100%". This guarantees the container to keep its dimensions.

Structure without Scroller:

┌────────────────────────────────────────────────────────────────────────┐
│  This is the container defined in the definition argument.             │
│  Accessible over env.container or env.$container                       │
│                                                                        │
│  isolation: isolate                                                    │
│  ┌──────────────────────────────────────────────────────────────────┐  │
│  │ div                                                              │  │
│  │ Here is the place where the widget will be initialized.          │  │
│  │ Accessible over env.element or env.$element                      │  │
│  │                                                                  │  │
│  │ height: 100%;                                                    │  │
│  │ width: 100%;                                                     │  │
│  │ position: relative;                                              │  │
│  │ overflow: hidden;                                                │  │
│  └──────────────────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────────────┘

In addition to the JavaScript-based widget, you can also create a Vue-based widget. In this case you have to provide a Vue application which will be instantiated.

You have to specify if the Vue application use a single root template or not. Depending on this the inner div described above is the root element (this.$el) of your vue application or just a parent container:

Single root Vue application:

┌────────────────────────────────────────────────────────────────────────┐
│  The parent containers and all styles will be                          │
│  constructed like with JavaScript-based widgets                        │
│  ┌──────────────────────────────────────────────────────────────────┐  │
│  │ div                                                              │  │
│  │                                                                  │  │
│  │ Root element of your Vue template                                │  │
│  │ Accessible over this.component.env.element or ...$element        │  │
│  └──────────────────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────────────┘

Vue with single root template

The variable this.component.env.element where you get normally the root element will not be available while mounting (and thus in the methods beforeCreate, created, beforeMount and mounted).

Multiple root Vue application:

┌────────────────────────────────────────────────────────────────────────┐
│  The parent containers and all styles will be                          │
│  constructed like with JavaScript-based widgets                        │
│  ┌──────────────────────────────────────────────────────────────────┐  │
│  │ div                                                              │  │
│  │ Accessible over this.component.env.element or ...$element        │  │
│  │                                                                  │  │
│  │  Multiple root elements of your Vue template:                    │  │
│  │  ┌────────────────────────────────────────────────────────────┐  │  │
│  │  │                                                            │  │  │
│  │  └────────────────────────────────────────────────────────────┘  │  │
│  │  ┌────────────────────────────────────────────────────────────┐  │  │
│  │  │                                                            │  │  │
│  │  └────────────────────────────────────────────────────────────┘  │  │
│  │  ┌────────────────────────────────────────────────────────────┐  │  │
│  │  │                                                            │  │  │
│  │  └────────────────────────────────────────────────────────────┘  │  │
│  │                                                                  │  │
│  └──────────────────────────────────────────────────────────────────┘  │
│                                                                        │
└────────────────────────────────────────────────────────────────────────┘

What's next?

Do whatever you want and build amazing interfaces within this.element!

Implementation Details

Controlling the DOM Structure and Initialization Phase

A Widget build the previous DOM structure and block the widget while initializing. Sometimes this is not needed. To control these features you have implement the following method:

1
2
3
4
5
6
7
8
import { Widget } from "@codecoupler/cc-ui";
export default class extends Widget {
  async prepare(env) {
    env.feature.scroll = false; //Disable scroll container
    env.feature.block = false; //Disable blocking while initializing
    return super.prepare(env);
  }
}

Reference

In addition to the common instance members described in the base classe Component a widget has the following:

Instance Properties

vue and vueApp

This properties will be accessible if the widget is Vue based. vue points to the Vue instance and vueApp to the Vue application object.

Back to top