Architecture

These scripts are pieces of JavaScript code that monitor field value changes, and define the logic for calculating values in dependent fields.

Imagine an invoice form with the fields Price, Quantity, and Total. To automatically calculate the total and display this value in the Total field, use this piece of code:

form.onChange(['Price', 'Quantity'])
  .setValue('Total', state => {
    const [price, quantity] = state.changes

    if (!price || !quantity)
          return null;

    return price.value * quantity.value;
  });

Let’s take a closer look. The script has a global FormProxy object called form, and it insures that the code interacts with a Pyrus form:

interface FormProxy {
  onChange(fieldNames: string[]): ChangeHandler;

  fetchSelfRegister(
    filterFn: (filter: RegisterFilter) => RegisterFilter,
    fieldNames: string[]
  ): Promise<RegisterResponse>;

  getDateWithTimezoneOffset(date: string): Date;
}

The onChange method takes the names of the fields that are going to change (Price and Quantity) as its first argument, then returns the ChangeHandler object.

You will find more information about the fetchSelfRegister method in Form register.

ChangeHandler defines the logic for calculating the value of the dependent field (Total), and it executes whenever a change occurs in any fields described in the onChange method.

interface ChangeHandler {
  setValue(
    fieldName: string,
    calcFunction: (state: FormState) => CompositeValue
  ): void;

  setValues(
    fieldNames: string[],
    calcFunction: (state: FormState) => CompositeValue[]
  ): void;

  setValueAsync(
    fieldName: string,
    calcFunction: (state: FormState) => Promise<CompositeValue>
  ): void;

  setValuesAsync(
    fieldNames: string[],
    calcFunction: (state: FormState) => Promise<CompositeValue[]>
  ): void;

  validate(
    fieldName: string,
    validateFunction: (state: FormState) => {errorMessage: string} | null
  ): void;

  validateAsync(
    fieldName: string,
    validateFunction: (state: FormState) => Promise<{errorMessage: string} | null>
  ): void;
}

The setValue method’s arguments are:

  • fieldNames — a list of field names whose values need to be calculated.
  • calcFunction — a function responsible for field value calculation.

calcFunction receives a FormState object as its only argument, then returns a new value (see Field value formats) for the calculated field described in the setValue method.

When you need to calculate the values of several fields based on the same data, use the setValues method. It takes an array of field names, while calcFunction returns an array of these field’s values.

If calculations require asynchronous operations (like waiting for the completion of the register request), use the asynchronous versions of the methods: setValueAsync and setValuesAsync. In this case, a Promise object, which will return the field values, is returned to calcFunction. You will find an example of how this can be used in Form register.

The validate and validateAsync methods allow for flexible field validation and error notifications. For more details, see Field validation.

FormState receives the values for Price and Quantity and uses them to calculate Total.

interface FormState {
  changes: FieldValue[];
  prev: FieldValue[];
}

The “changes” field contains an array of onChange’s current field values. The “prev” field contains an array of the calculable fields’ previous values.

Was this article helpful?