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.