Add a new Element type to the dynamic Controller
================================================
The dynamic controller component (DCC) supports different element types,
like ``button``, ``linechart`` and ``switch``.
In this example we will add the new element type ``label`` to this list.
This simple element will display a single labeled information like this:
.. image:: ../label.png
So beside an id and the type, we need to pass a title and a source for the
value via the DCC JSON specification:
.. code-block:: json
{
"id": "l-targetspeed",
"type": "label",
"title": "Target Speed (km/h)",
"source": {
"endpoint": "/$CONTROLLER/state",
"path": "target_speed"
}
}
If Cloe UI loads this specification, it will raise an error because the type
``label`` is unknown yet. So let's implement it!
Preparation
-----------
The prerequisite for a new element type is that a corresponding react component
exists. It is possible to define everything directly in the DCC, but in terms
of reusability and being 'React-ish', you should define it as an
individual component.
So we define a new react component named ``Label`` in a new file
``src/components/label.jsx`` :
.. code-block:: jsx
:linenos:
// The Label component represents one single key-value pair.
// It displays a value with it's key (label).
import React from "react";
function Label(props) {
const { label, value } = props;
return (
{label}
{value}
);
}
export default Label;
Our component takes two props, ``label`` and ``value`` (line 7) and
displays them in a bootstrap grid.
Implementation in DCC
---------------------
Now that the component is defined by itself, we can use it in the DCC.
The DCC is defined as a react class component called ``Controller`` in
``src/components/controller.jsx``.
The first step is to import our ``Label`` component outside of the
``Controller`` class:
.. code-block:: javascript
import Label from "./label";
For each element type, the class has a method which takes the specified
information (in our case mainly the title and source), and pass them over
to the right Component. This methods name's are prefixed with ``generate``,
e.g. the method to generate a button is named ``generateButton``.
So as second step, we add a new method ``generateLabel`` to the
``Controller`` class, which takes a ``labelElement`` as argument:
.. code-block:: jsx
generateLabel = (labelElement) => {};
The ``labelElement`` will be an object which includes all relevant information
which is needed to render it. It's basic structure is similar to it's JSON
specification. The only differences are in the ``sources`` property
and the new ``reactElement`` property. It looks like this:
.. code-block:: javascript
:linenos:
{
"id": "l-targetspeed",
"title": "Target Speed (km/h)",
"type": "label"
"sources": [{
"endpoint": "/$CONTROLLER/state",
"path": "target_speed",
"math": undefined,
"name": undefined
}]
"reactElement": undefined
}
The yet undefined ``reactElement`` is what is needed by Cloe UI to render
something. We will generate it with our ``generateLabel`` method.
So we need to pass the ``label`` and the correseponding value to the
``Label`` component.
The ``label`` is easy, we will take the ``labelElement.title`` property.
To get the value, we use a method called ``_genSourceValue(source)``.
Since ``labelElement.sources`` is of type array, we need to pass
``labelElement.sources[0]`` as argument:
.. code-block:: jsx
:linenos:
generateLabel = (labelElement) => {
const value = this._getSourceValue(labelElement.sources[0]);
const title = labelElement.title;
};
Now we can use our ``Label`` component, pass all needed information and
store it in ``labelElement.reactElement`` and return the updated element:
.. code-block:: jsx
:linenos:
generateLabel = (labelElement) => {
const value = this._getSourceValue(labelElement.sources[0]);
const title = labelElement.title;
labelElement.reactElement = (