Select to view content in your preferred language

Is there a way to keep a custom widget from loading until the map and layers finish loading?

435
4
09-05-2024 07:51 AM
DanielWebb
Frequent Contributor

We just upgraded to ArcGIS Enterprise 11.1 and I am playing with custom experience builder widgets.

I have a widget that loads, but only if the map and layers finish loading first. If the user clicks the button too soon the widget errors with a message

“Cannot read properties of null (reading 'view')”

(See screenshot attached).

I figured out that it happens because the app isn’t fully finished loading so the mapView is null.

const viewManager = MapViewManager.getInstance();
console.log(viewManager); // is not null if widget loaded too soon
const mapView = viewManager.getJimuMapViewById(viewManager.getAllJimuMapViewIds()[0]);
console.log(mapView); // returns null if widget loaded too soon

As long as the user waits long enough, mapView will not be null. But if pressed too quickly it is null.

In an Experience Builder React widget, is there a way to only load the widget after the map and layers finish loading? (Kind of like how the Esri JS SDK has the view.when, or something like that). Or is there some other way of getting the same result? That way, even if the user clicks the button too soon to open the widget, it will still load only after the map and layers finish and won’t error.

Thanks!

FYI: I am an extreme newbie with React and Experience Builder custom widgets.

0 Kudos
4 Replies
DavidSolari
Frequent Contributor

Is it possible to check if the map view is null in the render step of the appropriate component and return a placeholder fragment if it's null instead of the proper widget fragment? Haven't played with custom widgets much but if the view manager is passed into the component's props then React should handle the rest.

0 Kudos
DanielWebb
Frequent Contributor

Unfortunately, I’m an extreme newbie with React and experience builder widgets, so I don’t understand your thoughts.

Here is the beginning of my widget. Are you saying the mapView should be in the props of Widget somehow? Like next to the "AllWidgetProps<any>"

const Widget = (props: AllWidgetProps<any>) => {
    const viewManager = MapViewManager.getInstance();
    console.log(viewManager); // is not null if widget loaded too soon
    const mapView = viewManager.getJimuMapViewById(viewManager.getAllJimuMapViewIds()[0]);
    console.log(mapView); // returns null if widget loaded too soon

    return (
        <div></div>
    );
}

 or where the 

0 Kudos
DavidSolari
Frequent Contributor

I think the next best step is to look over this sample widget and see if you can adapt this pattern to a functional component. The React Reference should have examples of all hooks in class and function formats.

0 Kudos
JeffreyThompson2
MVP Regular Contributor
useEffect(() => {
		if (jimuMapView) {
			reactiveUtils
				.whenOnce(() => jimuMapView.view.ready)
				.then(() => {
					setMapReady(true)
				}
				)
		}

	}, [jimuMapView])

Almost all of my widgets contain a block of code like this. This useEffect function fires everytime the value of jimuMapView changes. If jimuMapView is truthy, it use the reactiveUtils from the API to wait for the mapView to be ready and that sets the value of my mapReady piece of state to true. All of my functional parts of my widget are usually down a level on the React tree waiting for mapReady to be true before loading.

GIS Developer
City of Arlington, Texas