Ruleset variables

Ruleset Variables is a new name for now deprecated User Settings concept.

Presentation rulesets have a concept called ruleset variables whose purpose is to allow modifying ruleset behavior during the session without having to change the ruleset itself. The values of ruleset variables can be accessed using ECExpressions in:

The advantages of using ruleset variables over values hardcoded into the ruleset are:

  • When used for creating a hierarchy, changing a ruleset variable causes only affected parts of the hierarchy to be re-created. Changing a rule in a ruleset causes the whole hierarchy to be re-created.

  • It's much more convenient and effective to pass a large number of IDs through a ruleset variable than it is to hardcode them into a ruleset. Ruleset variables are sent to the backend separately from the ruleset and that allows us to compress them when needed.

Using variables in rule condition

Using a ruleset variable in rule condition allows enabling and disabling specific rules based on something that can't be determined at the point of creating the ruleset, e.g. a user action.

The below example creates either a models' or an elements' hierarchy based on the value of ruleset variable.

By default the ruleset value is not set, which means neither of the two root node rules pass the condition. The result is empty hierarchy:

// The ruleset has two root node rules - one for models and one for elements. The one actually used
// depends on the value of `TREE_TYPE` ruleset variable, which can be changed without modifying the ruleset itself.
const ruleset: Ruleset = {
  id: "test",
  rules: [{
    ruleType: "RootNodes",
    condition: `GetVariableStringValue("TREE_TYPE") = "models"`,
    specifications: [{
      specType: "InstanceNodesOfSpecificClasses",
      classes: { schemaName: "BisCore", classNames: ["Model"] },
      arePolymorphic: true,
    }],
  }, {
    ruleType: "RootNodes",
    condition: `GetVariableStringValue("TREE_TYPE") = "elements"`,
    specifications: [{
      specType: "InstanceNodesOfSpecificClasses",
      classes: { schemaName: "BisCore", classNames: ["Element"] },
      arePolymorphic: true,
    }],
  }],
};

Empty Hierarchy

Setting the ruleset value to models creates a models' hierarchy:

await Presentation.presentation.vars(ruleset.id).setString("TREE_TYPE", "models");

Models' Hierarchy

Setting the ruleset value to elements creates an elements' hierarchy:

await Presentation.presentation.vars(ruleset.id).setString("TREE_TYPE", "elements");

Elements' Hierarchy

Using variables in instance filter

Using a ruleset variable in instance filter allows filtering instances at query time. This is useful when the filtering criteria depends on user actions.

The below example shows a hierarchy of elements grouped by class. When the element-ids variable is not set, the whole hierarchy is displayed. When the value is set to specific element IDs, the hierarchy is created only for those elements.

By default the ruleset value is not set - a hierarchy for all elements is created:

// The ruleset has a root node rule which loads all bis.Element instances, optionally filtered
// by ECInstanceId. The filter is controlled through `ELEMENT_IDS` ruleset variable.
const ruleset: Ruleset = {
  id: "test",
  rules: [{
    ruleType: "RootNodes",
    specifications: [{
      specType: "InstanceNodesOfSpecificClasses",
      classes: { schemaName: "BisCore", classNames: ["Element"] },
      arePolymorphic: true,
      instanceFilter: `NOT HasVariable("ELEMENT_IDS") OR GetVariableIntValues("ELEMENT_IDS").AnyMatch(id => id = this.ECInstanceId)`,
    }],
  }],
};

Empty Hierarchy

Setting the ruleset value to specific IDs creates the hierarchy only for specific elements:

await Presentation.presentation.vars(ruleset.id).setId64s("ELEMENT_IDS", ["0x1", "0x74", "0x40"]);

Filtered Elements' Hierarchy

Clearing the ruleset value brings us back to the initial unfiltered view:

await Presentation.presentation.vars(ruleset.id).unset("ELEMENT_IDS");

Elements' Hierarchy

Using variables in ECExpression-based value

Using a ruleset variable in ECExpression-based value makes the value customizable by users.

The below example shows a hierarchy that loads Spatial View Definition elements as root nodes. By default, when prefix variable is not set, node labels are created from CodeValue property of the element. When the prefix variable is set, it's value is used as a prefix for node labels.

By default the ruleset value is not set - CodeValue property value is used as the label:

// The ruleset has a root node rule which loads all bis.SpatialViewDefinition instances. There's
// also a label customization rule which optionally prefixes node labels with a ruleset variable value and
// an instance label override rule to clear default BIS label override rules. The prefix is
// controlled through the `PREFIX` ruleset variable.
const ruleset: Ruleset = {
  id: "test",
  rules: [{
    ruleType: "RootNodes",
    specifications: [{
      specType: "InstanceNodesOfSpecificClasses",
      classes: { schemaName: "BisCore", classNames: ["SpatialViewDefinition"] },
      arePolymorphic: true,
      groupByClass: false,
      groupByLabel: false,
    }],
  }, {
    ruleType: "LabelOverride",
    label: `IIF(HasVariable("PREFIX"), GetVariableStringValue("PREFIX") & " " & this.CodeValue, this.CodeValue)`,
  }, {
    ruleType: "InstanceLabelOverride",
    class: { schemaName: "BisCore", className: "SpatialViewDefinition" },
    values: [],
  }],
};

Spatial View Definitions

Setting the ruleset variable value makes it appear in front of every node's label:

await Presentation.presentation.vars(ruleset.id).setString("PREFIX", "test");

Spatial View Definitions - Prefixed Labels

Last Updated: 24 January, 2023