Select to view content in your preferred language

Access layer features and data in Experience Builder Widget Development

5056
21
11-02-2023 10:01 AM
Labels (1)
diplonics
Emerging Contributor
Long background in Openlayers but taking on the Experience Builder Widget development challenge and so far okay. However can't fathom how to access a layers data after its added to the map. Could someone point me to a tutorial or resource on what I thought I could easily where I want to generate a UI element containing some of the layer attribute data after it loads. So I need to get the data and loop through it. I can get the data fine and display it on the map but can't seem to access it through the layer, view or layerView objects.
 
Code currently using to get the data is as follows:

 

const layer = new this.GeoJSONLayer({
	url: requestURL,
	customParameters: {
		request: this.state.bbox,
	},
	title: "New data",
	renderer: {
		type: "simple",
		symbol: {
			type: "simple-line",
			width: 2,
			Color: "blue"
		}
	}
});
JimuMapView.view.map.add(layer);
// After the layer is created try to build UI element from layer data.
layer.on('layerview-create', (event) => {
	try{
		const results = event.layerView.queryFeatures();
		const graphics = results.features;
		console.log(graphics);				//Just returns null
	}catch (error){
		console.error("query failed: ", error);
	}
})

 

0 Kudos
21 Replies
JeffreyThompson2
MVP Frequent Contributor

Yes, that const [layer line was an error. It has been corrected in the React guide. The correct line there was.

const [layer, setLayer] = useState(item)
GIS Developer
City of Arlington, Texas
0 Kudos
diplonics
Emerging Contributor

Coming back to this after a week with loads of progress, got a great Widget built that does what we want...except...I can't preview it because of a load error which probably means I'll not be able to publish it as well.

So I took the code back to basics and am using your base example from here and same error shows up:
https://community.esri.com/t5/experience-builder-tips-and-tricks/react-for-experience-builder-develo...
In the Developer/Draft UI your code works fine (as does my widget) but once I try and preview it, which opens in a new tab, both widgets 'fail to load'.

Could you check if you are getting the same issue?

The featurelayer URL I'm using with your example code is:
'http://sampleserver6.arcgisonline.com/arcgis/rest/services/NapervilleShelters/FeatureServer/0'
The dev-console error stack is this.

diplonics_0-1700152457133.png

 



0 Kudos
JeffreyThompson2
MVP Frequent Contributor

https://developers.arcgis.com/experience-builder/guide/add-layers-to-a-map/#change-the-widget-name

Based on the error, I am guessing that you did not include jimu-arcgis in your dependencies in manifest.json as shown in the link.

GIS Developer
City of Arlington, Texas
0 Kudos
diplonics
Emerging Contributor

Yep, that fixed it, thanks again for your input and help on all bits, its appreciated.

0 Kudos
diplonics
Emerging Contributor

Just back working on this project and stuck on how to highlight a map feature in the GeoJson layer that has been added to the map as detailed in earlier post.
So, in code I have access to both the 'JimuMapView.view.map' and the 'layer' but what I need to do is when a feature is clicked in a table in my widget i need to highlight it in the map.
Each feature has a feature_id attribute that's unique and I can access from the table in my custom widget so I should be able to loop through the layers feature in the mapView and highlight it but what I've tried so far isn't working.
I'm currently trying this approach:
https://community.esri.com/t5/kotlin-maps-sdk-questions/selecting-a-feature-from-featurecollectionla...
but can't figure it out?

0 Kudos
JeffreyThompson2
MVP Frequent Contributor

That link is from a separate API, so the methods are going to be different. You should query the layer and then use the .highlight() method.

https://developers.arcgis.com/javascript/latest/api-reference/esri-views-layers-GeoJSONLayerView.htm...

GIS Developer
City of Arlington, Texas
0 Kudos
diplonics
Emerging Contributor

Hopefully another easy fix can be applied to help me again learn and raise my inexperienced React codebase skills!!!
I'm getting following error:

Load module error. Error: Module parse failed: The keyword 'yield' is reserved (86:28)
File was processed with these loaders:

Issue is I'm trying to recode various bits to fully understand scope etc., basically do things properly.

So I managed to use your suggestion of the .highlight() method which was a big help, thank you as per usual. However, I put it together as a hack that seemed to work but I'm certainly not sensibly implementing it as the layerView scope doesn't exist in numerous contexts.

Sample code below shows the that the error kicks in because of the await request line 17.

If I comment it out and use line 16 instead then things run fine for the table click situation to highlighting the map feature, however layerView is still null in lots of other contexts so I obviously have something scope wise badly wrong!!!

 

const layer = new this.GeoJSONLayer({
	url: requestURL,
	customParameters: {
		request: this.state.bbox,
	},
	title: "New data",
	renderer: {
		type: "simple",
		symbol: {
			type: "simple-line",
			width: 2,
			Color: "blue"
		}
	}
});
JimuMapView.view.map.add(layer);
//var layerView = null;   //THIS WORKS
const layerView = await jimuMapView.view.whenLayerView(layer);   //THIS DOES NOT WORK
// After the layer is created try to build UI element from layer data.
layer.on('layerview-create', (event) => {
	try{
		const results = event.layerView.queryFeatures();
		const graphics = results.features;
		console.log(graphics);				//Just returns null
	}catch (error){
		console.error("query failed: ", error);
	}
})
jimuMapView.view.whenLayerView(layer).then(function(layerView){console.log(layerView);});

 

0 Kudos
JeffreyThompson2
MVP Frequent Contributor

I'm not sure what you are trying to accomplish, so here is some general information you may find helpful.

The await keyword can only be used inside a function declared with the async keyword.

The layer and the layerView are not the same thing. Roughly speaking, the layer is the data and the layerView is how the data is displayed. In most cases, you should run queries on the layer, rather than the layerView.

GIS Developer
City of Arlington, Texas
0 Kudos
diplonics
Emerging Contributor

Thanks again and eventually worked it out to get what I need working. Into code exception handling now and stuck on the case where no GeoJSON features are returned. Is there an example of catching/handling errors you can point to.

const layer = new this.GeoJSONLayer({
	url: requestURL,
	customParameters: {
		request: this.state.bbox,
	},
	title: "New data",
	renderer: {
		type: "simple",
		symbol: {
			type: "simple-line",
			width: 2,
			Color: "blue"
		}
	}
});

JimuMapView.view.map.add(layer);

//Following code is actioned by a button click event to make a new GeoJson query and load it into the layer:
//bbox changes based on the mapview extents.
layer.customParameters.request = bbox;
layer.refresh();
const query = layer.createQuery();
query.where = "1=1";
layer.queryFeatures(query)
	.then(function(response){
		if(response.features.length > 0){
			console.log("The GeoJSON API has sent NEW data, Update Map & Widget UI!");
		}else{
			console.log("The GeoJSON API has sent NO data, Clear Map & reset widget UI!");
		}				
	}).catch(function(e){console.log(e);});

 

Below is an image of the console errors. When the widget first loads there is no GeoJson data. If the load data button is clicked a layer refresh occurs and is fine as long as features are returned, if none are returned then these errors occur and further updates to the layer fail. Is there a correct way to handle exception cases where a query that returns no features just clears the map and shows a message of 'no data top load'.

Screenshot 2024-02-27 110521.png

0 Kudos
JeffreyThompson2
MVP Frequent Contributor

If I understand your problem, you have code that functions and does additional analysis if the API returns data, but errors out if there is no data, and you want to know how to handle a no data senario. Practically, the best option would be to inform the user that there is no data to work with and allow them to start over. There are several ways to accomplish this (if/else, try/catch, or moving part of your code down the React tree), but they are all fundamentally just different ways to make an if statement. 

GIS Developer
City of Arlington, Texas
0 Kudos