Handling of complex data types
In many cases a control is intended to work with a complex data type, e.g. from the PLC. Alternatively, control configurations are to be created as an object or array. To do this, a JSON schema must be created and referenced accordingly in description.json.
However, the information in the schemas cannot be used directly in TypeScript. To do this, a TypeScript interface must be defined manually in your own source code.
Note: In old templates, modules TcHmi
was used instead of namespace TcHmi
. The resulting JavaScript code is exactly the same. However, this syntax is outdated and is therefore no longer used in newer templates.
The TypeScript interface should be defined within the namespace
area of the project name.
namespace TcHmi.Controls {
export namespace FrameworkPrjDatatype {
export class FrameworkPrj1Control extends TcHmi.Controls.System.TcHmiControl {
constructor(element: JQuery, pcElement: JQuery, attrs: TcHmi.Controls.ControlAttributeList) {
super(element, pcElement, attrs);
// more here
}
}
export interface plcValue {
/** Count Down on rising edge */
CountDown: boolean;
/** Load Start Value */
LOAD: boolean;
/** Start Value */
PV: number;
}
}
}
TcHmi.Controls.registerEx('FrameworkPrj1Control', 'TcHmi.Controls.FrameworkPrjDatatype', TcHmi.Controls.FrameworkPrjDatatype.FrameworkPrj1Control);
If the control still has the old module
syntax, this can simply be changed. To do this, simply replace the keyword module
with namespace
. If you do not want to do this, a new namespace
must be added in parallel to module
of the project name. The TypeScript interface can then be defined here.
module TcHmi {
export module Controls {
export module FrameworkPrjDatatypeOld {
export class FrameworkPrj1Control extends TcHmi.Controls.System.TcHmiControl {
// more here
}
}
export namespace FrameworkPrjDatatypeOld {
export interface plcValue {
/** Count Down on rising edge */
CountDown: boolean;
/** Load Start Value */
LOAD: boolean;
/** Start Value */
PV: number;
}
}
registerEx('FrameworkPrjTsDatatypes', 'TcHmi.Controls.FrameworkPrjDatatypeOld', FrameworkPrjDatatypeOld.FrameworkPrj1Control);
}
}
The data type is now known as TcHmi.Controls.FrameworkPrjDatatype.plcValue
. As the control class is in the same scope, the type can be accessed with the identifier FrameworkPrjDatatype.plcValue
.
An attribute setter and process function can look like the following, for example:
protected __value: FrameworkPrjDatatype.plcValue | undefined;
public setValue(valueNew: FrameworkPrjDatatype.plcValue | null) {
// convert the value with the value converter
let convertedValue = TcHmi.ValueConverter.toObject<typeof valueNew>(valueNew);
// check if the converted value is valid
if (convertedValue === null) {
// if we have no value to set we have to fall back to the defaultValueInternal from description.json
convertedValue = this.getAttributeDefaultValueInternal('Value') as FrameworkPrjDatatype.plcValue;
}
if (tchmi_equal(convertedValue, this.__value)) {
// skip processing when the value has not changed
return;
}
// remember the new value
this.__value = convertedValue;
// inform the system that the function has a changed result.
TcHmi.EventProvider.raise(this.__id + '.onPropertyChanged', { propertyName: 'Value' });
// call process function to process the new value
this.__processValue();
}
protected __processValue() {
if (this.__value) {
this.__value.CountDown; // known to TypeScript
this.__value.PV; // even tooltip “Start Value” is shown
}
}
Custom control administration objects can be defined and used in the same way.