diff --git a/packages/geoview-core/src/api/event-processors/event-processor-children/map-event-processor.ts b/packages/geoview-core/src/api/event-processors/event-processor-children/map-event-processor.ts index 267dad49b18..260bceefec1 100644 --- a/packages/geoview-core/src/api/event-processors/event-processor-children/map-event-processor.ts +++ b/packages/geoview-core/src/api/event-processors/event-processor-children/map-event-processor.ts @@ -1063,7 +1063,7 @@ export class MapEventProcessor extends AbstractEventProcessor { let configLayerEntryConfig; if (geoviewLayerConfig) { - configLayerEntryConfig = (geoviewLayerConfig as TypeGeoviewLayerConfig).listOfLayerEntryConfig.find( + configLayerEntryConfig = (geoviewLayerConfig as TypeGeoviewLayerConfig).listOfLayerEntryConfig?.find( (nextEntryConfig: TypeLayerEntryConfig) => nextEntryConfig.layerId === pathArray[1] ); for (let i = 2; i < pathArray.length; i++) { diff --git a/packages/geoview-core/src/geo/layer/layer.ts b/packages/geoview-core/src/geo/layer/layer.ts index b0737a2023c..2c7d6e3ce82 100644 --- a/packages/geoview-core/src/geo/layer/layer.ts +++ b/packages/geoview-core/src/geo/layer/layer.ts @@ -559,53 +559,88 @@ export class LayerApi { logger.logError(`Duplicate use of geoview layer identifier ${mapConfigLayerEntry.geoviewLayerId} on map ${this.getMapId()}`); } + /** + * TODO Add this function to utilties + * Gets all child paths from a parent path + * @param {string} parentPath - The parent path + * @returns {string[]} Child layer paths + */ + #getAllChildPaths(parentPath: string): string[] { + const parentLayerEntryConfig = this.getLayerEntryConfig(parentPath)?.geoviewLayerConfig.listOfLayerEntryConfig; + + if (!parentLayerEntryConfig) return []; + + function getChildPaths(listOfLayerEntryConfig: TypeLayerEntryConfig[]): string[] { + const layerPaths: string[] = []; + listOfLayerEntryConfig.forEach((entryConfig) => { + layerPaths.push(entryConfig.layerPath); + if (entryConfig.listOfLayerEntryConfig) { + layerPaths.push(...getChildPaths(entryConfig.listOfLayerEntryConfig)); + } + }); + return layerPaths; + } + + const layerPaths = getChildPaths(parentLayerEntryConfig); + return layerPaths; + } + /** * Refreshes GeoCore Layers - * @returns {Promise} A promise which resolves when done refreshing */ - reloadGeocoreLayers(): Promise { + reloadGeocoreLayers(): void { const configs = this.getLayerEntryConfigs(); const originalMapOrderedLayerInfo = MapEventProcessor.getMapOrderedLayerInfo(this.getMapId()); - const promisesOfGeoCoreGeoviewLayers: Promise[] = []; - - configs - .filter((config) => { - // Filter to just Geocore layers and not child layers - if (api.config.isValidUUID(config.geoviewLayerConfig.geoviewLayerId) && config.parentLayerConfig === undefined) { - return true; - } - return false; - }) - .forEach((config) => { - // Remove and add back in GeoCore Layers and return their promises - this.removeLayerUsingPath(config.layerPath); - const geoCore = new GeoCore(this.getMapId(), this.mapViewer.getDisplayLanguage()); - promisesOfGeoCoreGeoviewLayers.push(geoCore.createLayersFromUUID(config.geoviewLayerConfig.geoviewLayerId)); - }); - - return Promise.allSettled(promisesOfGeoCoreGeoviewLayers) - .then((promisedLayers) => { - promisedLayers - .filter((promise) => promise.status === 'fulfilled') - .map((promise) => promise as PromiseFulfilledResult) - .forEach((promise) => { - promise.value.forEach((geoviewLayerConfig) => { - this.addGeoviewLayer(geoviewLayerConfig); + const parentPaths: string[] = []; + + // Have to do the Promise allSettled so the new MapOrderedLayerInfo has all the children layerPaths + Promise.allSettled( + configs + .filter((config) => { + // Filter to just Geocore layers and not child layers + if (api.config.isValidUUID(config.geoviewLayerConfig.geoviewLayerId) && config.parentLayerConfig === undefined) { + return true; + } + return false; + }) + .map((config) => { + // Remove and add back in GeoCore Layers and return their promises + parentPaths.push(config.layerPath); + this.removeLayerUsingPath(config.layerPath); + return this.addGeoviewLayerByGeoCoreUUID(config.geoviewLayerConfig.geoviewLayerId); + }) + ) + .then(() => { + const originalLayerPaths = originalMapOrderedLayerInfo.map((info) => info.layerPath); + + // Prepare listeners for removing previously removed layers + parentPaths.forEach((parentPath) => { + function removeChildLayers(sender: LayerApi): void { + const childPaths = sender.#getAllChildPaths(parentPath); + childPaths.forEach((childPath) => { + if (!originalLayerPaths.includes(childPath)) { + sender.removeLayerUsingPath(childPath); + } }); - }); - const newMapOrderedLayerInfo = MapEventProcessor.getMapOrderedLayerInfo(this.getMapId()); - const originalLayerPaths = originalMapOrderedLayerInfo.map((layer) => layer.layerPath); - const childLayersToRemove = newMapOrderedLayerInfo - .map((layer) => layer.layerPath) - .filter((path) => !originalLayerPaths.includes(path)); - if (childLayersToRemove) { - childLayersToRemove.forEach((childPath) => { - this.removeLayerUsingPath(childPath); - }); - } + sender.offLayerAdded(removeChildLayers); + } + this.onLayerAdded(removeChildLayers); + }); + + // Prepare listeners for changing the visibility MapEventProcessor.setMapOrderedLayerInfo(this.getMapId(), originalMapOrderedLayerInfo); + originalMapOrderedLayerInfo.forEach((layerInfo) => { + function setLayerVisibility(sender: LayerApi, event: LayerLoadedEvent): void { + if (layerInfo.layerPath === event.layerPath) { + const { visible } = originalMapOrderedLayerInfo.filter((info) => info.layerPath === event.layerPath)[0]; + event.layer?.setVisible(visible, event.layerPath); + sender.offLayerLoaded(setLayerVisibility); + } + } + this.onLayerLoaded(setLayerVisibility); + }); }) - .catch((error) => logger.logError(error)); + .catch((err) => logger.logError(err)); } /** diff --git a/packages/geoview-core/src/geo/map/map-viewer.ts b/packages/geoview-core/src/geo/map/map-viewer.ts index fc1bcf8dcae..ab7b8c4c8ab 100644 --- a/packages/geoview-core/src/geo/map/map-viewer.ts +++ b/packages/geoview-core/src/geo/map/map-viewer.ts @@ -918,28 +918,26 @@ export class MapViewer { * * @param {TypeDisplayLanguage} displayLanguage - The language to use (en, fr) * @param {boolean} resetLayer - Optional flag to ask viewer to reload layers with the new localize language - * @returns {Promise<[void, void]>} + * @returns {Promise} */ - setLanguage(displayLanguage: TypeDisplayLanguage, reloadLayers?: boolean | false): Promise<[void, void]> { + async setLanguage(displayLanguage: TypeDisplayLanguage, reloadLayers?: boolean | false): Promise { // If the language hasn't changed don't do anything - if (AppEventProcessor.getDisplayLanguage(this.mapId) === displayLanguage) return Promise.resolve([undefined, undefined]); + if (AppEventProcessor.getDisplayLanguage(this.mapId) === displayLanguage) return; if (VALID_DISPLAY_LANGUAGE.includes(displayLanguage)) { - const promise = AppEventProcessor.setDisplayLanguage(this.mapId, displayLanguage); + await AppEventProcessor.setDisplayLanguage(this.mapId, displayLanguage); - // if flag is true, reload GeoCore layers + // if flag is true, reload just the GeoCore layers instead of reloading the whole map with current state if (reloadLayers) { - this.layer.reloadGeocoreLayers().catch((error) => logger.logError(error)); + this.layer.reloadGeocoreLayers(); } // Emit language changed event this.#emitMapLanguageChanged({ language: displayLanguage }); - // Return the promise - return promise; + return; } // Unsupported this.notifications.addNotificationError(getLocalizedMessage('validation.changeDisplayLanguage', displayLanguage)); - return Promise.resolve([undefined, undefined]); } /**