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.