Changed Elements API Tutorial
The Changed Elements API is a REST API that allows the consumer to inspect what elements have changed in an iModel between two versions of the iModel. In this tutorial, we will explore using the API operations and we will write an iTwin.js application to visualize change.
1. Set up your environment
To do this tutorial, it is recommended that you do the Web Application Quick Start tutorial first. This tutorial expects that you have a registered application as shown in the quick start tutorial.
This is the source code control system for the iTwin repositories.Tutorial Repository
This is the github repository that you will use in this tutorial. You should clone the
start branch as a starting point to follow along. If at any point you are unsure on how to setup the code demonstrated in the snippets, or just want to take a shortcut, the repository’s
main branch contains the finished tutorial application.
Clone starting point for tutorial
Finished tutorial application
This is our recommended editor and debugger tool for developing iTwin.js applications. It is free, open source and includes a GUI for working with GIT.Postman
If you want to test the REST API calls directly, you can use Postman or any other solution capable of sending HTTP requests. If you do it this way, you will require an authorization token for the requests to work.
To learn more about how authentication and authorization works in an iTwin powered application, check out the full documentation on how to obtain the token.
This is the first operation of the API and is used to enable change tracking of an iModel.
The API requires the
changedelements:modify scope to be added to your App. It can be added to your apps in the Developer Portal.
2.1.1 What is change tracking and why do we need it?
An iModel evolves over time. Every time a design file is changed and the iModel is synchronized, new Changesets are published to the iModel, updating the iModel data.
An iModel may contain graphical elements that are related to business data. For example, let’s think about a piece of equipment:
This equipment may be displayed in an iModel with a bare-bones Geometric Element, however, business data that relates to it (like the pump diameter in the image above), exists under the properties of a different non-graphical element.
A changeset may contain changes to the equipment’s related pump diameter property, but the geometric counterpart of the equipment will not contain a change. To be able to find which elements relate to which change, you can use the Changed Elements API.
The Changed Elements API will track the iModel for changes, and when a Named Version is created, the API will find all related elements that have changed in each of the changesets and store a summary of them in the cloud.
2.1.2 How do I enable tracking in the Changed Elements API?
The API has an operation to enable the changed elements feature for an iModel. As mentioned before, for this operation to work, your App needs to have the scope:
Here is an example request that shows how to enable the API’s change tracking for an iModel, you would just need to replace the context Id, iModel Id and authorization token with your own.
The body should contain a JSON object with a
enable property, and it must be either true or false as shown in the example above.
Here is the documentation for this operation.
Example HTTP Request for Enable Change Tracking Operation
2.1.3 My iModel is being tracked for change, now what?
Once change tracking is enabled for your iModel, whenever a new Named Version gets created, either by a design application or a Connector, the API will process the changesets and store the results of what elements have changed in your iModel.
This operation can take time, and the time it takes is dependent on data complexity and size. It is recommended to use a small iModel to do this tutorial if you are following along, as a very large iModel may take hours to process if it has never been processed and has a lot of data.
The next operation allows us to query the API to get the elements that have changed after processing is ready. To use this operation, you must provide the start and end changeset Ids that you want to obtain results for. To get changeset Ids, you can use Get iModel Changesets API.
The API requires the
changedelements:read scope to be added to your App. It can be added to your apps in the Developer Portal
2.2.1 Using the API to get changed elements
Here is an example request that shows how to get the changed elements between two changesets, ensure to replace the context Id, iModel Id, start changeset Id, end changeset Id and authorization token with your own.
This operation will return a JSON object that contains which elements have changed between the two given changeset Ids. The returned JSON corresponds to the ChangedElements interface. We will explore the format a bit more in the Changed Elements JSON Section. Here’s an example of the data returned for a single element that changed:
In the example above, even though Changeset 2 is the changeset related to Named Version A, to get what has changed between A and B, start changeset should be Changeset 3 and end changeset should be Changeset 4, as Changeset 2 is already applied to the iModel in Named Version A.
Another thing to keep in mind is that if you want to obtain changed elements for a single changeset, since the range is inclusive, you can provide the same changeset Id for start and end changesets, and it will return the elements for the given changeset.
Here’s the documentation for this operation.
Example HTTP Request for Get Comparison Operation
Example result from the Get Comparison Operation
3. Putting it to work
Now that we have covered how the API works, we will use it to create a simple application that can visualize change.
We will implement a simple widget that will allow us to use both operations of the changed elements API. It will have a button to enable change tracking, a dropdown that will allow us to pick a named version and another button to visualize the differences between the current version and the one selected in the dropdown.
After cloning the
main branch of the repository, create a new .tsx file and call it
ChangedElementsWidget.tsx. We are going to write a react hook that will allow us to query the named versions of the iModel, so that we can populate the dropdown list to select our version to compare against.
The named versions object also contains the Id of the changesets, which we will use later on to do the API calls.
Now that we have a working react hook for that purpose, we can write our widget component. The widget will have a label, a react select dropdown and two buttons. We will write the button’s onClick handlers later on in the tutorial, so we will leave them empty for now.
To stylize the UI component a little bit, create a
ChangedElementsWidget.scss file and add the styles shown in the code snippet.
We can now proceed to add the widget to the viewer application.
Write a react hook for getting named versions
Write the widget UI component
SCSS for the UI Component
Now that we have the component ready, we need to create a UiItemsProvider that will feed the our widget to the viewer. Create a new file
ChangedElementsUiProvider.tsx to put the code in. Then, import the
ChangedElementsUiProvider in our
App.tsx file, and add the provider to the
uiProviders array prop of the
Viewer react component.
Then, we must pass the provider to the viewer’s react component, and it should now show in right panel like so:
If you want to verify that you have added the code in the right place, you can check the final results for App.tsx, ChangedElementsWidget.tsx and ChangedElementsUiProvider.tsx. Keep in mind that the ChangedElementsWidget.tsx code in the repository is already in its final state, containing button handlers that we will be adding later on in this tutorial.
Create a UI Items Provider
Import the ChangedElementsUiProvider in App.tsx
Add the UI Items Provider to the viewer in App.tsx
To use the API in our viewer, we will need to create a client class that interfaces with the API and gives us the proper results.
Create a new file called
ChangedElementsClient.ts and create a class like shown in the code snippet. We are first going to write functions to create the correct URLs for our operations based on some input parameters, like our iModel’s Id and changeset Ids.
Now that we have the scaffolding for the client class, let’s add functions for calling the API for each operation.
enableChangeTracking function will use the Enable Change Tracking endpoint to enable or disable tracking for an iModel.
Both operations require an authorization token. The repository comes with a simple
AuthorizationClient class that will get the necessary tokens as long as your
.env file is properly setup as explained in the README of the repo
Here’s what the ChangedElementsClient.ts file should look like when you are done with this section.
Changed Elements Client
Now, we must implement the onClick handlers of the widget buttons so that they use the client and call the necessary API endpoints. First, ensure you import the
ChangedElementsClient to be used in the
For enabling change tracking, all we need to do is use the client’s
enableChangeTracking method we wrote earlier. Paste the code in the
onEnableTracking callback that we left blank earlier in Section 3.1. For this to work, we just need to pass the
iModel object and
true to the client’s function. If you have not enabled change tracking on your iModel yet, do so now. Keep in mind that as mentioned in section 2.1.3, processing may take a while, so take a break and get some coffee to ensure that the API processes your iModel.
For visualizing changed elements, we are going to need to use the client’s
getComparison method. This requires us to pass the
endChangesetId. We can obtain the
iModel from the passed props of the widget. The
endChangesetId we can obtain by looking at the iModel’s current changeset. For
startChangesetId, we need to use the
selectedVersion variable we setup in the widget that should contain the changeset Id of the named version that got selected by the user. Paste the code in the
onVisualizeChangedElements callback that we left blank earlier in Section 3.1. If you get a
404 response from the Get Comparison operation, it means the API has not yet processed your iModel, and you must wait.
If authorization has been properly setup, you should obtain results from the API. To display the results in the viewport, let’s emphasize the elements that have changed on the screen. We can use the EmphasizeElements class, which is a FeatureOverrideProvider that will highlight the elements on the viewport.
changedElements.elements is an array that contains the element Ids of all elements that have changed in the iModel between the changesets that we are looking at. Here’s more information about the ChangedElements result.
Here’s what the ChangedElementsWidget.tsx file should look like when you are done with this section.
Import the ChangedElementsClient class in ChangedElementsWidget
Enable Change Tracking Button Handler
Visualize Changed Elements Button Handler
By now, you should have changed elements being emphasized in your view, but it would be better if we colorize them by their operation codes, see DbOpcode.
To be able to colorize the elements, we will implement our own FeatureOverrideProvider. Create a new file
ChangedElementsFeatureOverrides.ts and follow the code snippet to the right.
The provider’s constructor finds which elements are inserted or updated based on their DbOpcode. Then, it implements the
addFeatureOverrides function that will colorize inserted elements as green, updated elements as blue and make everything else transparent gray.
Now that we have a feature override provider that will colorize our elements properly, let’s use it in our
onVisualizeChangedElements button callback. Import the class in
Before adding a provider to the viewport, t’s important to drop any feature override providers from the viewport before we add one to ensure we start with a clean viewport each time.
You should now be able to see the elements colorized, showing inserted elements as green and updated elements as blue whenever we click the visualize button:
Here’s what the ChangedElementsFeatureOverrides.ts file should look like when you are done with this section.
Changed Elements Feature Override Provider
Updated Visualize Changed Elements Button Callback
We will cover working with properties from Changed Elements API in a different tutorial, but here’s an overview of what’s provided in the API:
The API returns a
properties array that contains the
EC Property Access Strings of any properties that had changes between the two versions being queried. The
properties array is 2-dimensional, the first index corresponds to the element you are looking at, the second index will allow you to iterate through all properties that changed in the element.
As explained in the Enabling Change Tracking Section, the properties of an element may not live in the element itself, so we can’t simply query for its value using ECSQL, the element Id and the property access string.
To properly inspect an elements properties, including properties that do not exist on the element, we need to use iTwin.js Presentation Library, which is out of scope for this tutorial.
The change data also contains the
oldChecksums arrays. Each property of an element will have a matching new and old checksum. These arrays are useful to quickly check if the property value indeed has changed, or if it has flipped back and forth to the same value between versions.
ChangedElements class is defined in the @bentley/imodeljs-common package.
As mentioned before, this interface contains different arrays. Let’s go over each of the arrays and what they are:elements
Contains the element Ids of the changed elements. This is useful if you want to query the iModel for more information about the element.classIds
Contains the ECClass Ids of the changed elements. This is useful if you want to access specific properties of the element that are in its ECClass.opcodes
Contains the operation codes that tells us if the element was inserted, updated or deleted in the change. See DbOpcodetype
Contains the type of change that occurred to the element. This number is a bitflag, and can be used to know whether the element had property changes, geometric changes, placement changes, indirect changes and/or hidden property changes.modelIds
Contains the model Ids of the changed elements. This is useful for visualization purposes, like ensuring the model the changed element resides in is displayed in the viewport.properties
Contains the property accessor string names of changed properties an element may have. This property accessor string can be used in conjunction with the element’s class Id to obtain the property value.oldChecksums
Contains the old checksum for the property value of the index that matches the property array. This is useful to determine using newChecksums array, whether the property value has indeed changed in the before and after states of the iModel. This is useful because there are cases in which a property may be flipped back and forth, and you may still want to know it was touched, but you can determine whether the change is valuable using a simple checksum comparison.newChecksums
Contains the new checksum for the property value of the index that matches the property arrayparentIds
Contains the parent Id of the element. If the element does not have a parent, this id will be “0”parentClassIds
Contains the ECClass Id of the parent of the element. If the element does not have a parent, this id will be “0”
Congratulations on completing this tutorial, at this point you should have been able to visualize change using the API! In conclusion, the Changed Elements API can help you understand what elements have changed in your iModel and how they have changed between the given changesets. You could use this API to generate reports, visualize change using an iTwin.js application like we did in this tutorial, or review properties that have changed on the elements that you find relevant in your iModel.
More resources that you may likeCreate React App
Set up a modern web app by running one command.iTwin Viewer React
The iTwin Viewer is a configurable iTwin.js viewer that offers basic tooling and widgets out-of-the-box and can be further extended through the use of iModel.js extensions. This package contains the Viewer as a React component and some additional Typescript API’s.iTwin Viewer Create React App TemplateBentley React Scripts
This is the iTwin.js fork of react-scripts.