Calculated properties specification

TypeScript type: CalculatedPropertiesSpecification.

This content modifier allows including additional calculated properties into the content.

Attributes

Name Required? Type Default
label Yes string
value No ECExpression
type No "string" | "int" | "long" | "dateTime" | "boolean" | "bool" | "double" "string"
categoryId No string | CategoryIdentifier No override
renderer No RendererSpecification No override
editor No PropertyEditorSpecification No override
priority No number 1000
extendedData No { [key: string]: ECExpression }

Attribute: label

Specifies label of the calculated property. Supports localization.

Type string
Is Required Yes
// There's a content rule for returning content of given `bis.Subject` instance. The produced content is customized to
// additionally have a calculated "My Calculated Property" property.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "Content",
      specifications: [
        {
          specType: "SelectedNodeInstances",
          calculatedProperties: [
            {
              label: "My Calculated Property",
              value: `123`,
            },
          ],
        },
      ],
    },
  ],
};

Example of using "label" attribute

Attribute: value

Defines an expression to calculate the value. The expression can use ECInstance and Ruleset Variables symbol contexts.

Type ECExpression
Is Required No
Default Value undefined
// There's a content rule for returning content of given `bis.GeometricElement3d` instance. The produced content is
// customized to additionally have a calculated "Element Volume" property whose value is calculated based on
// element's `BBoxHigh` and `BBoxLow` property values.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "Content",
      specifications: [
        {
          specType: "SelectedNodeInstances",
          calculatedProperties: [
            {
              label: "Element Volume",
              value: "(this.BBoxHigh.x - this.BBoxLow.x) * (this.BBoxHigh.y - this.BBoxLow.y) * (this.BBoxHigh.z - this.BBoxLow.z)",
            },
          ],
        },
      ],
    },
  ],
};

Example of using "value" attribute

Attribute: type

Specifies return type of the calculated property. Presentation library tries to map the type of the evaluated expression to the requested type. If evaluated expression cannot be converted to the specified type, an error will be thrown when requesting content with the error message: Calculated property evaluated to a type that couldn't be converted to requested type. For example, if the specified type is dateTime for the expression 2 * 2, an error would be thrown, since evaluated expression would have a type of int.

Type "string" | "int" | "long" | "dateTime" | "boolean" | "bool" | "double"
Is Required No
Default Value "string"
// There's a content rule for returning content of given `bis.GeometricElement3d` instance. The produced content is customized to
// additionally have a calculated "My Calculated Property" property with a custom return "type"
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "Content",
      specifications: [
        {
          specType: "SelectedNodeInstances",
          calculatedProperties: [
            {
              label: "My Calculated Property",
              value: "2+2",
              type: "int"
            },
          ],
        },
      ],
    },
  ],
};

Example of using "type" attribute

Attribute: categoryId

The attribute allows moving the property into a different category. There are several options:

  • Reference a category by ID used in PropertyCategorySpecification in the current context. The current context contains categories specified in the same content specification or content modifiers that are applied on the same or base ECClass as this property specification.

  • Move to DefaultParent category. This is useful when using with related properties, to avoid putting them inside a special related class category and instead show them next to properties of the source class.

  • Move to Root category. This is useful when using with related properties, to avoid putting them inside a special related class category and instead show them in the root category.

See property categorization page for more details.

Type string | CategoryIdentifier
Is Required No
Default Value No override
// There's a content rule for returning content of given `bis.Subject` instance. The produced content is customized to
// additionally have a calculated "My Calculated Property" property that is placed into a custom category by
// assigning it a `categoryId`.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "Content",
      specifications: [
        {
          specType: "SelectedNodeInstances",
          propertyCategories: [
            {
              id: "custom-category",
              label: "Custom",
            },
          ],
          calculatedProperties: [
            {
              label: "My Calculated Property",
              value: "123",
              categoryId: "custom-category",
            },
          ],
        },
      ],
    },
  ],
};

Example of using "categoryId" attribute

Attribute: renderer

Custom property renderer specification that allows assigning a custom value renderer to be used in UI. The specification is used to set up Field.renderer for this property and it's up to the UI component to make sure appropriate renderer is used to render the property.

See Custom property value renderers page for a list of available renderers or how to register a custom one.

Type RendererSpecification
Is Required No
Default Value No override
// There's a content rule for returning content of given `bis.Subject` instance. The produced content is customized to
// additionally have a calculated "My Calculated Property" property with a custom "my-renderer" renderer.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "Content",
      specifications: [
        {
          specType: "SelectedNodeInstances",
          calculatedProperties: [
            {
              label: "My Calculated property",
              value: "123",
              renderer: {
                rendererName: "my-renderer",
              },
            },
          ],
        },
      ],
    },
  ],
};
// Ensure the calculated property field is assigned the "my-renderer" renderer
const content = await Presentation.presentation.getContentIterator({
  imodel,
  rulesetOrId: ruleset,
  keys: new KeySet([{ className: "BisCore:Subject", id: "0x1" }]),
  descriptor: {},
});
expect(content!.descriptor.fields).to.containSubset([
  {
    label: "My Calculated property",
    renderer: {
      name: "my-renderer",
    },
  },
]);

Attribute editor

Custom property editor specification that allows assigning a custom value editor to be used in UI.

Type PropertyEditorSpecification
Is Required No
Default Value No override
// There's a content rule for returning content of given `bis.Subject` instance. The produced content is customized to
// additionally have a calculated "My Calculated Property" property with a custom "my-editor" editor.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "Content",
      specifications: [
        {
          specType: "SelectedNodeInstances",
          calculatedProperties: [
            {
              label: "My Calculated property",
              value: "123",
              editor: {
                editorName: "my-editor",
              },
            },
          ],
        },
      ],
    },
  ],
};
// Ensure the calculated property field is assigned the "my-editor" editor
const content = await Presentation.presentation.getContentIterator({
  imodel,
  rulesetOrId: ruleset,
  keys: new KeySet([{ className: "BisCore:Subject", id: "0x1" }]),
  descriptor: {},
});
expect(content!.descriptor.fields).to.containSubset([
  {
    label: "My Calculated property",
    editor: {
      name: "my-editor",
    },
  },
]);

Attribute: priority

Assign a custom Field.priority to the property. It's up to the UI component to make sure that priority is respected - properties with higher priority should appear before or above properties with lower priority.

Type number
Is Required No
Default Value 1000
// There's a content rule for returning content of given `bis.Subject` instance. The produced content is customized to
// additionally have a "My Calculated Property" property with priority set to `9999`. This should make the property
// appear at the top in the UI, since generally properties have a priority of `1000`.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "Content",
      specifications: [
        {
          specType: "SelectedNodeInstances",
          calculatedProperties: [
            {
              label: "My Calculated Property",
              value: `123`,
              priority: 9999,
            },
          ],
        },
      ],
    },
  ],
};
priority: 9999 priority: -9999
Example of using "priority" attribute set to 9999 Example of using "priority" attribute set to -9999

Attribute: extendedData

A map of ECExpressions whose evaluation results are used as extended data values.

Type { [key: string]: ECExpression }
Is Required No
// There's a content rule for returning content of given `bis.Subject` instance. The produced content is customized to
// additionally have a calculated "My Calculated Property" property that has extended data assigned.
const ruleset: Ruleset = {
  id: "example",
  rules: [
    {
      ruleType: "Content",
      specifications: [
        {
          specType: "SelectedNodeInstances",
          calculatedProperties: [
            {
              label: "My Calculated Property",
              value: "123",
              extendedData: {
                extendedDataInt: "2*2",
                extendedDataStr: "\"xxx\""
              },
            },
          ],
        },
      ],
    },
  ],
};
// Ensure that the calculated property field has `extendedData` items assigned to it.
const content = await Presentation.presentation.getContentIterator({
  imodel,
  rulesetOrId: ruleset,
  keys: new KeySet([{ className: "BisCore:Subject", id: "0x1" }]),
  descriptor: {},
});
expect(content!.descriptor.fields).to.containSubset([
  {
    label: "My Calculated Property",
    extendedData: {
      extendedDataInt: 4,
      extendedDataStr: "xxx"
    },
  },
]);

Last Updated: 17 September, 2024