Custom node specification
TypeScript type: CustomNodeSpecification.
Returns a static custom-defined node that's not based on an ECInstance.
Attributes
Name | Required? | Type | Default |
---|---|---|---|
Node values | |||
type |
Yes | string |
|
label |
Yes | string |
|
description |
No | string |
"" |
imageId |
No | string |
"" |
Filtering | |||
hideExpression |
No | ECExpression | "" |
hideIfNoChildren |
No | boolean |
false |
hideNodesInHierarchy |
No | boolean |
false |
suppressSimilarAncestorsCheck |
No | boolean |
false |
Ordering | |||
priority |
No | number |
1000 |
Misc. | |||
hasChildren |
No | "Always" | "Never" | "Unknown" |
"Unknown" |
nestedRules |
No | ChildNodeRule[] |
[] |
Attribute: type
Specifies node type, which is assigned to node's key. The type can be used:
- In ECExpressions by using the NavNode.Type symbol.
- In code through BaseNodeKey.type.
The given value is often used in a condition of another child node rule to assign children to this node.
Type | string |
Is Required | Yes |
// The ruleset has a root node specification that returns a single custom node with specified parameters. There's
// also a child node rule that assigns the child based on root node's type.
const ruleset: Ruleset = {
id: "example",
rules: [
{
ruleType: "RootNodes",
specifications: [
{
specType: "CustomNode",
type: "T_ROOT_NODE",
label: "My Root Node",
},
],
},
{
ruleType: "ChildNodes",
condition: `ParentNode.Type = "T_ROOT_NODE"`,
specifications: [
{
specType: "CustomNode",
type: "T_CHILD_NODE",
label: "My Child Node",
},
],
},
],
};
Attribute: label
Specifies node label. This is a string value that may be localized.
Type | string |
Is Required | Yes |
// The ruleset has a root node specification that returns a single custom node with specified parameters.
const ruleset: Ruleset = {
id: "example",
rules: [
{
ruleType: "RootNodes",
specifications: [
{
specType: "CustomNode",
type: "T_MY_NODE",
label: "My Node",
},
],
},
],
};
Attribute: description
Specifies the value of Node.description property, which is a string that may be localized. UI component displaying the node may choose whether and how to surface this information to users.
Type | string |
Is Required | No |
Default Value | "" |
// The ruleset has a root node specification that returns a single custom node and assigns it a description.
const ruleset: Ruleset = {
id: "example",
rules: [
{
ruleType: "RootNodes",
specifications: [
{
specType: "CustomNode",
type: "T_MY_NODE",
label: "My Node",
description: "My node's description",
},
],
},
],
};
Attribute: imageId
Specifies node's image ID. If set, the ID is assigned to Node.imageId and it's up to the UI component to decide what to do with it.
Type | string |
Is Required | No |
Default Value | "" |
// The ruleset has a root node specification that returns a single custom node and assigns it an image identifier.
const ruleset: Ruleset = {
id: "example",
rules: [
{
ruleType: "RootNodes",
specifications: [
{
specType: "CustomNode",
type: "T_MY_NODE",
label: "My Node",
imageId: "my-icon-identifier",
},
],
},
],
};
// Verify that node with correct image identifier is returned
const nodes = await Presentation.presentation.getNodesIterator({ imodel, rulesetOrId: ruleset }).then(async (x) => collect(x.items));
expect(nodes)
.to.have.lengthOf(1)
.and.to.containSubset([
{
imageId: "my-icon-identifier",
},
]);
Attribute: hideNodesInHierarchy
When true
, nodes produced by this specification are omitted and their children appear one hierarchy level higher.
Type | boolean |
Is Required | No |
Default Value | false |
// This ruleset produces a hierarchy that consists of two custom nodes. The parent node is hidden by
// `hideNodesInHierarchy` attribute, thus its child appears one hierarchy level higher.
const ruleset: Ruleset = {
id: "example",
rules: [
{
ruleType: "RootNodes",
specifications: [
{
specType: "CustomNode",
type: "parent",
label: "Parent",
hideNodesInHierarchy: true,
},
],
},
{
ruleType: "ChildNodes",
condition: `ParentNode.Type = "parent"`,
specifications: [
{
specType: "CustomNode",
type: "child",
label: "Child",
},
],
},
],
};
hideNodesInHierarchy: false |
hideNodesInHierarchy: true |
---|---|
Attribute: hideIfNoChildren
Specifies whether the node created through this specification should be hidden if it has no child nodes.
Type | boolean |
Is Required | No |
Default Value | false |
// The ruleset contains root node specifications for two custom nodes which are only
// displayed if they have children. One of them has children and the other - not, so
// only one of them is displayed
const ruleset: Ruleset = {
id: "example",
rules: [
{
ruleType: "RootNodes",
specifications: [
{
specType: "CustomNode",
type: "2d",
label: "2d Elements",
hideIfNoChildren: true,
},
{
specType: "CustomNode",
type: "3d",
label: "3d Elements",
hideIfNoChildren: true,
},
],
},
{
ruleType: "ChildNodes",
condition: `ParentNode.Type = "2d"`,
specifications: [
{
specType: "InstanceNodesOfSpecificClasses",
classes: { schemaName: "BisCore", classNames: ["GeometricElement2d"], arePolymorphic: true },
},
],
},
{
ruleType: "ChildNodes",
condition: `ParentNode.Type = "3d"`,
specifications: [
{
specType: "InstanceNodesOfSpecificClasses",
classes: { schemaName: "BisCore", classNames: ["GeometricElement3d"], arePolymorphic: true },
},
],
},
],
};
hideIfNoChildren: false |
hideIfNoChildren: true |
---|---|
Attribute: hideExpression
When specified ECExpression evaluates to true
, nodes produced by this specification are omitted and their children appear one hierarchy level higher.
Type | ECExpression |
Is Required | No |
Default Value | "" |
// The ruleset contains root node specifications for two custom nodes which are only
// displayed if they have children. One of them has children and the other - not, so
// only one of them is displayed
const ruleset: Ruleset = {
id: "example",
rules: [
{
ruleType: "RootNodes",
specifications: [
{
specType: "CustomNode",
type: "2d",
label: "2d Elements",
hideExpression: `ThisNode.HasChildren = FALSE`,
},
{
specType: "CustomNode",
type: "3d",
label: "3d Elements",
hideExpression: `ThisNode.HasChildren = FALSE`,
},
],
},
{
ruleType: "ChildNodes",
condition: `ParentNode.Type = "2d"`,
specifications: [
{
specType: "InstanceNodesOfSpecificClasses",
classes: { schemaName: "BisCore", classNames: ["GeometricElement2d"], arePolymorphic: true },
},
],
},
{
ruleType: "ChildNodes",
condition: `ParentNode.Type = "3d"`,
specifications: [
{
specType: "InstanceNodesOfSpecificClasses",
classes: { schemaName: "BisCore", classNames: ["GeometricElement3d"], arePolymorphic: true },
},
],
},
],
};
hideExpression evaluates to false |
hideExpression evaluates to true |
---|---|
Attribute: suppressSimilarAncestorsCheck
Specifies whether similar ancestor nodes' checking should be suppressed when creating nodes based on this specification. See more in Infinite Hierarchies Prevention page.
Type | boolean |
Is Required | No |
Default Value | false |
// The ruleset contains a root node specification that returns the root `bis.Subject` node. Also, there are two
// child node rules:
// - For any `bis.Model` node, return its contained `bis.Element` nodes.
// - For any `bis.Element` node, return its children `bis.Model` nodes.
// Children of the root `bis.Subject` are all in the single `bis.RepositoryModel` and some of their children are in the same
// `bis.RepositoryModel` as their parent. This means the `bis.RepositoryModel` node has to be repeated in the hierarchy, but
// that wouldn't happen due to duplicate nodes prevention, unless the `suppressSimilarAncestorsCheck` flag is set.
const ruleset: Ruleset = {
id: "example",
rules: [
{
ruleType: "RootNodes",
specifications: [
{
specType: "InstanceNodesOfSpecificClasses",
classes: { schemaName: "BisCore", classNames: ["Subject"] },
instanceFilter: `this.ECInstanceId = 1`,
groupByClass: false,
groupByLabel: false,
},
],
},
{
ruleType: "ChildNodes",
condition: `ParentNode.IsOfClass("Model", "BisCore")`,
specifications: [
{
specType: "RelatedInstanceNodes",
relationshipPaths: [
{
relationship: { schemaName: "BisCore", className: "ModelContainsElements" },
direction: "Forward",
},
],
groupByClass: false,
groupByLabel: false,
},
],
},
{
ruleType: "ChildNodes",
condition: `ParentNode.IsOfClass("Element", "BisCore")`,
specifications: [
{
specType: "RelatedInstanceNodes",
relationshipPaths: [
[
{
relationship: { schemaName: "BisCore", className: "ElementOwnsChildElements" },
direction: "Forward",
},
{
relationship: { schemaName: "BisCore", className: "ModelContainsElements" },
direction: "Backward",
},
],
],
suppressSimilarAncestorsCheck: true,
groupByClass: false,
groupByLabel: false,
},
],
},
],
};
Attribute: priority
Controls the order in which specifications are handled — specification with higher priority value is handled first. If priorities are equal, the specifications are handled in the order they appear in the ruleset.
Type | number |
Is Required | No |
Default Value | 1000 |
// This ruleset produces a list of `bis.PhysicalModel` and `bis.SpatialCategory` instances and groups them by
// class. "Spatial Category" group will appear first because it has been given a higher priority value.
const ruleset: Ruleset = {
id: "example",
rules: [
{
ruleType: "RootNodes",
specifications: [
{
specType: "InstanceNodesOfSpecificClasses",
priority: 1,
classes: { schemaName: "BisCore", classNames: ["PhysicalModel"], arePolymorphic: true },
},
{
specType: "InstanceNodesOfSpecificClasses",
priority: 2,
classes: { schemaName: "BisCore", classNames: ["SpatialCategory"], arePolymorphic: true },
},
],
},
],
};
Attribute: hasChildren
Generally, when a node is created, the rules engine has to determine whether it has children before returning it. This requires evaluating child node rules and, usually, executing additional queries. This attribute allows telling the engine that nodes created by this specification always or never have children, which may substantially improve performance of creating nodes in cases when getting child nodes is expensive.
In case when the attribute value "lies":
When set to
Always
, the returned nodes always have Node.hasChildren set totrue
. Requesting children for such nodes returns empty list. It's up to the UI component to handle the case of parent node saying it has children but data source not returning any.When set to
Never
, the returned nodes always have Node.hasChildren set tofalse
. Requesting children for such nodes returns empty list even if there are child node rules that define children for it.
Type | "Always" | "Never" | "Unknown" |
Is Required | No |
Default Value | "Unknown" |
// This ruleset produces a hierarchy of a single root node that hosts a list of `Model` instances. Assuming all
// iModels contain at least one model, the result of this ruleset can be computed quicker by setting
// `hasChildren` attribute to `"Always"`.
const ruleset: Ruleset = {
id: "example",
rules: [
{
ruleType: "RootNodes",
specifications: [
{
specType: "CustomNode",
type: "T_ROOT_NODE",
label: "My Root Node",
hasChildren: "Always",
},
],
},
{
ruleType: "ChildNodes",
condition: `ParentNode.Type="T_ROOT_NODE"`,
specifications: [
{
specType: "InstanceNodesOfSpecificClasses",
classes: [{ schemaName: "BisCore", classNames: ["Model"], arePolymorphic: true }],
},
],
},
],
};
hasChildren: "Always" |
hasChildren: "Never" |
---|---|
Attribute: nestedRules
Specifications of nested child node rules that allow creating child nodes without the need of supplying a condition to match the parent node.
This is useful when the same instance node at different hierarchy levels needs to have different child nodes. Specifying a child node rule at the root level with condition to match the instance ECClass makes the rule create children for all nodes of that ECClass. When that's not desired, different child node rules may be specified as nested rules for specifications that return instance nodes of the same ECClass - that makes them have different children.
Type | ChildNodeRule[] |
Is Required | No |
Default Value | [] |
// The ruleset contains two root nodes' specifications:
// - The first one returns `bis.SpatialCategory` nodes
// - The second one returns `bis.PhysicalModel` nodes and also has a nested child node rule
// that creates a static "child" node.
// Nested rules apply only to nodes created by the same specification, so the static "child"
// node is created only for the `bis.PhysicalModel`, but not `bis.SpatialCategory`.
const ruleset: Ruleset = {
id: "example",
rules: [
{
ruleType: "RootNodes",
specifications: [
{
specType: "InstanceNodesOfSpecificClasses",
classes: [{ schemaName: "BisCore", classNames: ["SpatialCategory"] }],
groupByClass: false,
},
{
specType: "InstanceNodesOfSpecificClasses",
classes: [{ schemaName: "BisCore", classNames: ["PhysicalModel"] }],
groupByClass: false,
nestedRules: [
{
ruleType: "ChildNodes",
specifications: [
{
specType: "CustomNode",
type: "T_CHILD",
label: "child",
},
],
},
],
},
],
},
],
};
Last Updated: 15 May, 2024