Handling von komplexen Datentypen
Oft soll ein Control mit einem komplexen Datentypen beispielsweise aus der PLC arbeiten. Alternativ sollen Control-Konfiguration als ein Objekt oder Array erstellt werden. Hierfür muss ein JSON-Schema erstellt und entsprechend in der description.json referenziert werden.
Jedoch sind die Informationen in den Schemata nicht direkt in TypeScript nutzbar. Hierfür muss händisch ein TypeScript-Interface im eigenen Quelltext definiert werden.
Hinweis: In alten Templates wurde modules TcHmi
statt namespace TcHmi
genutzt. Der resultierende JavaScript code ist exakt gleich. Diese Syntax ist jedoch veraltet und wird daher in neueren Templates nicht mehr verwendet.
Das TypeScript-Interface sollte innerhalb des namespace
Bereichs des Projektnamens definiert werden.
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);
Hat das Control noch die alte module
Syntax so kann diese einfach umgestellt werden. Dazu muss nur das Schlüsselwort module
durch namespace
ersetzen. Möchte man dies nicht tun, so muss parallel zu module
des Projektnamens ein neues namespace
ergänzt werden. Hier kann dann das TypeScript-Interface definiert werden.
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);
}
}
Nun ist der Datentyp unter dem Namen TcHmi.Controls.FrameworkPrjDatatype.plcValue
bekannt. Da die Control-Klasse im gleichen Ausführungskontext (Scope) liegt, kann auf den Typen mit dem Bezeichner FrameworkPrjDatatype.plcValue
zugegriffen werden.
Eine Attribut-Setter- und Process-Funktion kann damit beispielsweise aussehen wie im Folgenden gezeigt:
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
}
}
Auch eigene Verwaltungsobjekte des Controls können so definiert und einfach genutzt werden.