2017 June Release

Extended property definitionsPermanent link for this heading

An extended property definition allows you to define initialization values, to assign triggers to and to define constraints for your properties.

The following syntax example depicts the structure of extended property definitions.

Syntax

datatype reference modifiers {
  // Definition of an initialization value
  init = initvalue;

  // Definition of the access type required to read the property
  accget = getaccesstype;
  // Definition of the access type required to write the property
  accset = setaccesstype;

  // Trigger that is called when the property is created
  ctor = constructortriggeraction;
  // Trigger that is called when the value of the property is read
  get = getvaluetriggeraction;
  // Trigger that is called when the value of the property is written
  set = setvaluetriggeraction;
  // Trigger that is called when the value of the property is copied
  copy = copytriggeraction;

  // Value constraint
  value = expression {
    ...
  }
  // Filter constraint
  filter = expression {
    ...
  }
  // Filter constraint in a search form
  searchfilter = expression {
    ...
  }

  // Behavior in form pages: Check if property is visible
  visible = expression {
    ...
  }
  // Behavior in form pages: Check if property is changeable
  changeable = expression {
    ...
  }
  // Behavior in form pages: Check if property must be defined
  mustbedef = expression {
    ...
  }
  // Behavior in form pages: Validate property
  validate = expression {
    ...
  }
  // Behavior in form pages: Execute if value of property has changed
  uichange = expression {
    ...
  }
  // Behavior in form pages: Execute if value or property has changed in a search form
  uisearchchange = expression {
    ...
  }
  // Behavior in form pages: Access types for the property
  accset = expression {
    ...
  }
  // Behavior in form pages: Access types for a line of the property
  accsetline = expression {
    ...
  }
  // Behavior in form pages: Weight to display the property
  weight = expression {
    ...
  }
  // Behavior in form pages: Control style of the property
  controlstyle = expression {
    ...
  }
  // Behavior in form pages: Control options of the property
  controloptions = expression {
    ...
  }
}

For a description of all behaviors in form pages, see Table 14: Behaviors allowed within a layout block.

Initializing a property with a valuePermanent link for this heading

Using the init keyword, you can assign an initialization value to a property. The property is initialized with this value when you create a new instance of the object class the property is assigned to.

In addition to static initialization values, you can also use app.ducx expression language to calculate the value used for initializing a property. An expression block is required to define an initialization expression.

Example

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  class Order : CompoundObject {
    datetime orderdate readonly(ui) {
      // initialization with an expression block
      // example of a static initialization for datetime:

      // init = 2010-10-10T09:13:27;
      init = expression {
        coonow;
      }
    }
    OrderState orderstate readonly(ui) {
      init = OS_PENDING;
    }
    string ordershortdescription {
      init = "Please enter a description text!";
    }
    integer(3) orderitems readonly(ui) {
      init = 0;
    }
  }
}

Protecting a property with access typesPermanent link for this heading

A property can be protected with an access type for reading the property value and with an access type for changing the property:

  • The accget keyword is used to assign an access type for reading the property value. When protected by an access type for reading the property value, the property is only displayed if the access type is granted to the user by the object’s ACL.
  • The accset keyword is used to assign an access type for changing the property value. When protected by an access type for changing the property value, the property may only be changed if the access type is granted to the user by the object’s ACL.

Both the access type for reading and for changing the property value are optional.

Example

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  class Order : CompoundObject {
    Product[] orderedproducts not null {
      accget = AccTypeReadComp;
      accset = AccTypeChangeComp;
    }
  }
}

Assigning triggers to a propertyPermanent link for this heading

Triggers are actions that are invoked or “fired” automatically when a predefined event occurs. Each trigger has assigned a specific Fabasoft Folio action prototype listing the parameters that are passed to the implementation of the trigger action when it is called.

Keyword

Description

ctor

The constructor trigger is fired when the property is created. A constructor trigger action must have assigned the prototype COOSYSTEM@1.1:AttrConstructorPrototype.

linector

The line constructor trigger is fired when a new entry is created in a compound property. A line constructor trigger action must have assigned the prototype COOSYSTEM@1.1:AttrLineConstructorPrototype.

dtor

The destructor trigger is fired when the property is destroyed. A destructor trigger action must have assigned the prototype COOSYSTEM@1.1:AttrDestructorPrototype.

get

The get value trigger is fired after the property value is read from the database. A get value trigger action must have assigned the prototype COOSYSTEM@1.1:AttrGetPrototype.

set

The set value trigger is fired before the property value is written to the database. A set value trigger action must have assigned the prototype COOSYSTEM@1.1:AttrSetPrototype.

copy

The copy trigger is fired when an object containing the property is duplicated. A copy trigger action must have assigned the prototype COOSYSTEM@1.1:AttrCopyPrototype.

display

The display trigger is fired to format the property value for being displayed in a list view column. A display trigger action must have assigned the prototype COOSYSTEM@1.1:AttrGetDispPrototype.

search

The search trigger is fired when searching for values in the property. A search trigger action must have assigned the prototype COOSYSTEM@1.1:AttrSearchPrototype.

getver

The get versioned value trigger is fired when a version of the property value is read. A get versioned value trigger action must have assigned the prototype COOSYSTEM@1.1:AttrGetVersionPrototype.

fixver

The fix version trigger is fired when a version of the property value is created. A fix version trigger action must have assigned the prototype COOSYSTEM@1.1:AttrFixVersionPrototype.

delver

The delete version trigger is fired when a version of the property is deleted. A delete version trigger action must have assigned the prototype COOSYSTEM@1.1:AttrDelVersionPrototype.

restver

The restore version trigger is fired when a version of the property value is restored. A restore version trigger action must have assigned the prototype COOSYSTEM@1.1:AttrRestVersionPrototype.

archive

The archive trigger is fired when the property value is archived. An archive trigger action must have assigned the prototype COOSYSTEM@1.1:AttrArchivePrototype.

restore

The restore trigger is fired when the property value is being restored from an archive. A restore trigger action must have assigned the prototype COOSYSTEM@1.1:AttrRestArchivePrototype.

Table 6: Property triggers supported by Fabasoft app.ducx

Example

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  class Order : CompoundObject {
    // The value of the ID property of an order must not be copied when
    // an order object is duplicated

    unsigned integer(6) orderid {
      copy = NoOperation;
    }
  }
}


For further information on how to implement trigger actions, please consult chapter “Implementing triggers”.

Assigning constraints to a propertyPermanent link for this heading

Fabasoft Folio uses integrity and value constraints for calculating and validating values and to prevent invalid data entry into a property.

Fabasoft app.ducx currently supports following types of constraints:

  • Value constraints are useful for automatically calculated property values such as the grand total of an order or the number of order positions.
  • Filter constraints allow you to limit the selectable values for object pointer properties.
  • Validation constraints are typically expressed as conditions or measurements that must remain true as the user uses your solution.
  • User interface change constraints are evaluated when the value of an object pointer property is changed by the user, and can be used to trigger the re-evaluation of filter constraints or to set or clear the values of other properties.

Defining value constraints for a propertyPermanent link for this heading

A value constraint can be defined for the automatic calculation of a property value.

The keyword value is used for defining a value constraint where the app.ducx expression language must be used for the implementation.

Value constraints only make sense for calculated properties that cannot be changed by the user. Therefore, in most cases, properties with value constraints should also be set to volatile and readonly using appropriate property modifiers. If the property is not read-only the app.ducx expression must have a result that can store the changeable value (e.g. a property).  Additionally value constraints cannot be used within compound properties.

Please note that volatile properties do not show up in the search dialog box by default unless you attach a search trigger action to the property as demonstrated in the example.

When implementing a value constraint in app.ducx expression language, the current object can be accessed using the local scope this or global scope ::this. The calculated value that should be displayed in the property must be passed back as the return value of the expression.

In this example, the total value of all individual order positions of an order is calculated and displayed in a property with a value constraint.

Example

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  struct OrderPosition {
    Product product not null;
    unsigned integer quantity not null;
  }

  class Product : BasicObject {
    mlname;
    string[] productdescription;
    currency unitprice;
  }

  class Order : CompoundObject {
    OrderPosition[] orderpositions;
    currency ordertotal readonly volatile {
      value = expression {
        // Add up the price of the order positions
        currency @total = 0;

        for (OrderPosition @position : orderpositions) {
          Product @product = @position.product;
          if (@product != null) {
            @total += @product.unitprice * @position.quantity;
          }
        }
        // Return the grand total
        return @total;
      }
    }
  }
}

Defining filter constraints for a propertyPermanent link for this heading

Filter constraints allow you to limit the values that are selectable in an object pointer property.

The keyword filter or searchfilter is used for defining a filter constraint. The app.ducx expression language must be used for implementing the filter constraint. Search filters are used to reduce available objects of object pointer properties in context of a search.

There are two distinct variants of filter constraints that have different scopes depending on the data type of the return value of the filter expression:

  • Object list filter constraints
  • Boolean filter constraints

Note:

  • COOSYSTEM@1.1:attrfilterexpr
    A Fabasoft app.ducx Expression that determines or filters the possible selection of objects in an object pointer property. If used in conjunction with COOSYSTEM@1.1:AttrFilterCheckSet this Fabasoft app.ducx Expression is used to test the value of a property (of any type).
  • COOSYSTEM@1.1:attrsearchfilterexpr
    This filter is evaluated if CAM_SEARCH is passed in the parameter mode to the action COOSYSTEM@1.1:LocalObjectsGet. Additionally the transaction variable TV_SEARCHOBJCLASSES of type OBJECT is provided to be able to specify already chosen object classes in the search filter. The transaction variable contains the chosen object class (several in case of a quick search).

Object list filter constraintsPermanent link for this heading

An object list filter constraint is an expression returning a list of objects. For properties with an object list filter constraint, users can only select values out of the list of permitted values.

For an object list filter constraint, the object containing the object pointer property can be accessed using the local scope this. The global scope ::this contains a list of objects that should be filtered, i.e. after a quick search operation in the object pointer property control. If empty, the Fabasoft app.ducx Expression should retrieve a meaningful default for objects that are usable as a value for the property.

If an object list filter is terminated with the exception COOSYSTEM@1.1:COOSTERR_BREAK, the default behavior is provided. This meens, that fitting objects that have been recently used, are provided as the filter result.

Note: The type of the expression must be determinable before the expression is evaluated. To provide a precise type, a cast ot OBJECTLIST() is sometimes helpful.

Boolean filter constraintsPermanent link for this heading

A Boolean filter constraint is evaluated on each of the objects that would be selectable in an object pointer property based on the definition of allowed object classes for the property. If the filter expression returns true, the object is included in the list of selectable values displayed to users. Otherwise, the object is filtered out and cannot be selected.

For a Boolean filter constraint, the local scope this contains the object that is to be selected and the global scope ::this contains the object containing the object pointer property.

For instance, if a Boolean filter constraint is defined for an object pointer property for selecting users in a Fabasoft Folio Domain containing 300 user objects, the filter expression would be evaluated up to 300 times as it is evaluated for each user object.

In the example, there are three object classes: product, vendor, and order. An instance of vendor has a list of products sold by the vendor. An order contains an object pointer property pointing to a vendor, and a list of products ordered from this vendor. For the order’s vendor object pointer property, a Boolean filter constraint has been defined only allowing the user to select vendors that actually sell products. Moreover, the list of ordered products has attached an object list filter constraint that limits the selectable products to the list of products offered by the vendor referenced in the vendor object pointer property.

Example

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  class Product : BasicObject {
    string productid not null;
    User defaultagent;
  }

  class Vendor : CompoundObject {
    Product[] offeredproducts;
  }

  class Order : CompoundObject {
    Vendor vendor not null {
      // Boolean filter:
      // Only a vendor offering products can be selected.

      filter = expression {
        offeredproducts != null;
      }
    }
    Product[] orderedproducts not null {
      // Object list filter:
      // If <vendor> is valid and <offeredproducts> contain values,
      // these values can be selected.

      filter = expression {
        vendor.offeredproducts;
      }
    }
    User agent not null {
      // Object list filter with default behavior:
      // If there is a quick search result in ::this,
      // this is used whether the user found is a default agent or not.

      // If no default agents are configured for the ordered products,
      // the default behavior is performed.

      filter = expression {
        if (::this) {
          return OBJECTLIST(::this);
        }
        User[] @agents = orderedproducts.defaultagent;
        if (!@agents) {
          throw #COOSTERR_BREAK;
        }
        OBJECTLIST(@agent);
      }
    }
  }
}


When a value, filter, validation or user interface change constraint is evaluated, the transaction variables of software component COOSYSTEM@1.1 listed in the next table provide you with information on the path to the currently selected property.

Transaction Variable

Description

TV_ATTRPATHATTRDEFS

TV_ATTRPATHATTRDEFS contains the property path to the currently selected property.

For example, if the object pointer property APPDUCXSAMPLE@200.200:product in the third row of the compound property APPDUCXSAMPLE@200.200:orderpositions of an order is selected, TV_ATTRPATHATTRDEFS contains an object list consisting of the elements APPDUCXSAMPLE@200.200:orderpositions and APPDUCXSAMPLE@200.200:product.

TV_ATTRPATHINDICES

TV_ATTRPATHINDICES contains the zero-based indices of the selected rows to the currently selected property.

For example, if the object pointer property APPDUCXSAMPLE@200.200:product in the third row of the compound property APPDUCXSAMPLE@200.200:orderpositions of an order is selected, TV_ATTRPATHINDICES contains an integer list consisting of the elements 2 and 0.

Table 7: Transaction variables exposing path information

The following example demonstrates how to access the transaction variables provided by software component COOSYSTEM@1.1.

Example

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;
  import FSCFOLIO@1.1001;

  class Product : BasicObject {
    mlname;
    string[] productdescription;
    currency unitprice;
  }

  class Vendor : CompoundObject {
    Product[] offeredproducts;
  }

  struct OrderPosition {
    Vendor vendor;
    Product product {
      // This filter constraint limits the selectable products so that only
      // products offered by the selected vendor can be selected in the

      //
APPDUCXSAMPLE@.200.200:product property
      filter = expression {
        Product[] @products = null;
        integer[] @line = #TV.TV_ATTRPATHINDICES[0];
        Object @order = this;
        OrderPosition @orderpositionaggr = @order.orderpositions[@line];
        if (@orderpositionaggr != null) {
          Object @vendor = @orderpositionaggr.vendor;
          if (@vendor != null) {
            @products = @vendor.offeredproducts;
          }
        }
        @products;
      }
    }
    integer quantity;
  }

  class Order : BasicObject {
    OrderPosition[] orderpositions;
  }
}

Defining validation constraints for a propertyPermanent link for this heading

A validation constraint is an app.ducx expression that is evaluated to check whether the value entered into the property is valid in order to prevent invalid data entry into a property.

The expression must return a Boolean value. The return value true signals that the value entered by the user is valid. If the expression returns false, an error message is displayed on the form page containing the property requiring the user to correct the entered value.

Alternatively, the expression can also throw an exception for displaying a custom error message in case the validation fails.

The local scope contains the vApp state dictionary. The global scope contains a dictionary holding the keys listed in the next table.

Key

Description

value

The value key stores the current value of the property.

root

The root key stores the object containing the property.

parent

This key stores the parent of the property. If the property is part of a compound type, the parent is holding the compound property. If the property is not embedded within a compound property, the parent key holds the object containing the property. Thus, for properties that are not part of a compound property, the value stored in the parent key is equal to the value stored in the root key.

attribute

The attribute key contains the property definition.

Table 8: Global scope for validation expressions

Example

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;
  import FSCFOLIO@1.1001;

  class Project : CompoundObject {
    // Validation constraint ensures that project priority must be in
    // the range from 1 to 10

    unsigned integer(2) priority not null {
      validate = expression {
        ::value >= 1 && ::value <= 10;
      }
    }
    // COOSYSTEM@1.1:CheckWorkDay throws an exception to show a custom
    // error message if the date is not set to a work day in the

    // future

    datetime kickoffmeeting not null {
      validate = expression {
        ::root.CheckWorkDay(datetime(::value).local, true);
        return true;
      }
    }
    // Validation constraint throwing a custom error message
    date deadline not null {
      validate = expression {
        if (::value > coonow) {
          throw #COODESK@1.1:InValidDate;
        }
        else {
          true;
        }
      }
    }
  }
}


Defining user interface change constraints for a property

A user interface change constraint can be defined in order to trigger the re-evaluation of filter constraints or to set or clear the values of other properties.

The keywords uichange (value gets changed), uisearchchange (value gets changed in context of a search) and uiselchange (object gets selected) are used for defining a user interface change constraint. The weight constraint can be used to change the background color of an object. The app.ducx expression language must be used to implement a user interface change constraint.

The local scope contains the vApp state dictionary. When implementing a user interface change constraint in app.ducx expression language, a dictionary holding the keys listed in the previous table is made available in the global scope ::this. The expression must return the value true to trigger a round-trip to the Fabasoft Folio Web Service, which is necessary for the re-evaluation of filter constraints.

In the following example, the invoice date, the payment date and the processing state properties are cleared if the object pointer property referencing the order is changed.

Example

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  class<ContentObjectClass> Invoice : ContentObject {
    Order invoiceorder {
      uichange = expression {
        ::root.invoicestate = "IS_PENDING";
        ::root.invoicedate = null;
        ::root.invoicepaymentdate = null;
      }
    }
    date invoicedate;
    date invoicepaymentdate;
    InvoiceState invoicestate readonly(ui);
  }
}

Object pointer property containing childrenPermanent link for this heading

Object pointer properties can be set as child, if the referenced object values do not exist as separate entities; but have a meaning only as part of the container object. For child properties the following are the default values:

  • copy is COOSYSTEM@1.1:NoOperation,
  • accget is COOSYSTEM@1.1:AccTypeReadComp,
  • accset is COOSYSTEM@1.1:AccTypeChangeComp,
  • fixver is COOSYSTEM@1.1:AttrChildrenFixManualVersion,
  • COOSYSTEM@1.1:attrrecursion is false.

Example

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  class Order : BasicObject {
    OrderPosition[] orderpositions {
      child = true;
      ...
    }

  }
}

After an upload to the configured web service, a recycle is necessary, because GetChildredAttrDef collects the child information of the class attributes only at the first call of the class for performance reason.

Object pointer property describing a hierarchyPermanent link for this heading

Object pointer properties can be set as hierarchy, if the referenced object values are of a similar class as the container so that the values are in a hierarchical context. When selecting a value for a hierarchy property in a search form, the hierarchy relations can be specified in the user interface.

Example

objmodel APPDUCXSAMPLE@200.200
{
  import COOSYSTEM@1.1;

  class Order : BasicObject {
    Order baseorder {
      hierarchy = true;
      ...
    }

    Order[] suborders {
      hierarchy = true;
      ...
    }

  }
}