Issue with loadSubtreeFromModel
and Node Visibility in Dynamically Loaded Linked Models
We’re dynamically loading linked models using the following logic:
const subRootNodeId = gfxResObject.index === 0 && !this.isExternal
? [0]
: await this.model.loadSubtreeFromModel(this.viewer.linkedModelsNodeId, gfxResObject.fileName);
Sometimes this results in the following error:
IafGraphicsResourceManager.loadGraphicsResourceByIndex failed for /fileName 03-230071-0000100916-WOR-CON-MDL-000001_4.scz
/rootNodeId -2 /subRootNodeId undefined
Error: Bad model: Could not find master model key.
My Questions:
-
Under what circumstances does
loadSubtreeFromModel
returnundefined
and throw theBad model: Could not find master model key
error? -
After calling
loadSubtreeFromModel
, is there a recommended approach to ensure the loaded nodeIds are fully functional — especially for visibility control? -
Why might
setNodesVisibility(viewer, nodeIds, true/false)
fail to update visibility for some dynamically loaded nodes Sometimes frequently?
getViewNodeIdsOfActiveCategory = async () => {
let activeNodeIds = new Set();
const modelComposition = this.iafViewer.state?.modelComposition?._properties || {};
const categories = modelComposition.categories || [];
const activeCategories = categories.filter(cat => cat.isSelected && !cat.isDeleted);
for (const category of activeCategories) {
const linkedNodeIds = await this.getViewNodeIdsByCategory(category.id);
if (linkedNodeIds?.length) {
activeNodeIds = IafSet.Union(activeNodeIds, linkedNodeIds);
}
}
return [...activeNodeIds];
};
getViewNodeIdsByCategory = async (categoryId) => {
let linkedNodeIds = [];
const modelVersionId = this.dbModelVersionId;
const categoryLinkedViewIds = this.searchViewIdsByCategory(categoryId);
for (const viewId of categoryLinkedViewIds) {
const key = this.getViewNodeCacheKey(viewId, modelVersionId);
let cacheEntry = this.viewToNodeIdMap.get(key);
const gfxResObject = this.csdlMapByViewId.get(viewId);
if (!gfxResObject?.loaded) {
await this.loadGraphicsResourceByViewId(viewId);
cacheEntry = this.viewToNodeIdMap.get(key);
if (!cacheEntry) continue;
}
if (!Array.isArray(cacheEntry.linkedNodeIds) || !cacheEntry.linkedNodeIds.length) {
this.iafViewer.allChildren = [];
this.iafViewer.getAllChildren(cacheEntry.viewFetchPointNodeId, this.iafViewer._viewer);
cacheEntry.linkedNodeIds = this.iafViewer.allChildren;
this.viewToNodeIdMap.set(key, cacheEntry);
// if (this.iafViewer.iafDatabaseManager._enablePersistence) {
// await this.saveGraphicsCache();
// } else {
IafStorageUtils.saveGraphicsCache(this.viewer);
// }
}
linkedNodeIds = IafSet.Union(linkedNodeIds, cacheEntry.linkedNodeIds);
}
this.categoryToNodeIdsMap.set(categoryId, linkedNodeIds);
return linkedNodeIds;
};
toggleVisibilityByCategory = async (layerName, isVisible) => {
const oldNodeIds = this.categoryToNodeIdsMap.get(layerName) || [];
const newNodeIds = await this.getViewNodeIdsByCategory(layerName);
const allActiveNodeIds = await this.getViewNodeIdsOfActiveCategory();
if (isVisible) {
const added = IafSet.Difference(newNodeIds, oldNodeIds);
const removed = IafSet.Difference(oldNodeIds, newNodeIds);
if (added.length > 0) {
await this.iafViewer.setNodesVisibility(this.viewer, added, true);
}
if (removed.length > 0) {
const trulyRemoved = removed.filter(nodeId => !allActiveNodeIds.includes(nodeId));
await this.iafViewer.setNodesVisibility(this.viewer, trulyRemoved, false);
}
if (added.length === 0 && removed.length === 0 && newNodeIds.length > 0) {
await this.iafViewer.setNodesVisibility(this.viewer, newNodeIds, true);
}
} else {
let nodeIdsToHide = IafSet.Difference(newNodeIds, allActiveNodeIds);
if (newNodeIds.length === 0 && (allActiveNodeIds.length === 0 || oldNodeIds.length > 0)) {
nodeIdsToHide = oldNodeIds;
}
if (nodeIdsToHide.length > 0) {
await this.iafViewer.setNodesVisibility(this.viewer, nodeIdsToHide, false);
this.viewer.graphicsResources?.categoryToNodeIdsMap?.delete(layerName);
}
}
await this.overrideVisibilityForSelection(isVisible);
await this.iafViewer.setHiddenElements();//RRP PLAT-3855 - On demand loading of linked models - Hidden Elements
await this.updateBoundingBox('toggleVisibilityByCategory');
}
Looking forward to your insights — thank you!