Select to view content in your preferred language

Temporarily setting feature_layer graphic attribute values.

326
3
Jump to solution
06-27-2023 02:36 PM
Rhiannon
New Contributor II

I am attempting to rewrite a map from 3.13 to 4.26 and am a little stuck.

We have a service that contains a map of our state counties, with attributes "COUNTYNAME" and "render_Data".

Users of our website select a year and a category from dropdowns, click a "View Map" button, and the map renders with a ClassBreaksRenderer that colors the counties based on the rate the thing they selected happened in their chosen year in each county. When they hover over a county, it shows a popup that gives the exact rate.

On the service, the "render_Data" value is empty. That field is meant to hold the rate value, but the rate values aren't known until the user clicks View Map and our database is queried to bring back the rates for the year/category the user is interested in.

I apologize if I'm using the wrong terminology, but I believe what I want to do after the user clicks the View Map button is:
Go to our database and get the list of rates for the chosen year/category. This returns as json data that has the county name and rate (render_Data) for each county.
Get the feature layer from the service and create a client-side copy. (When I say "client-side copy", I mean I don't want to apply the following changes to the source/service, I want them to be temporary for the single user and disappear when the page refreshes).
Loop through the counties in the client-side feature layer and set the render_Data attribute to the matching rate attribute in the json returned from the database (matching on the county name, because both the json and the feature layer have a county name attribute/field).
Tell the ClassBreaksRenderer and PopupTemplate to look at the render_Data attribute that was just populated.
Load (or maybe refresh?) the map/view.

This seems like something there might be sample code for already, I'm just having trouble finding it.
I'm getting stuck on the timing/ordering of events. I'm also not sure if things like queryFeatures() and applyEdits() are going back to the original source, or if they can/are used on the temporary object I'm working with.

I made a codepen to lay out the basic idea, simplified as much as possible.
I'm not sure at which point I would loop though the feature_layer.graphic.attributes and update the render_Data value, and how exactly that works.

https://codepen.io/rhip/pen/zYMZGZP

Can anybody point me in the right direction? 

0 Kudos
1 Solution

Accepted Solutions
JoelBennett
MVP Regular Contributor

The technical answer to the question in your second post is no.  In 3.x of the API, a FeatureLayer would immediately begin retrieving its service info as soon as you instantiate it, but in 4.x, it doesn't do so until after it's added to a View.  Therefore, since no features would have been retrieved between those two lines, there'd be nothing for you to update.

Fortunately, there are still multiple ways you could accomplish what you're trying to do, and one way in particular stands out above the rest because (1) your code shows you already have the external JSON data with county-to-rate information loaded before adding the layer to the map, and (2) your layer already has a predefined empty field waiting to hold the appropriate value (render_Data).  Your problem therefore is that you need to update that field after the application receives the FeatureLayer's data, but before the FeatureLayer processes it and renders it on the map.

The SDK provides the means to do exactly that with the RequestInterceptor.  To use a RequestInterceptor, you create one and add it to the "interceptors" property of the esri.config.request object.  The "urls" value of your interceptor would be "https://gis.mo.gov/arcgis01/rest/services/DMH/DMH_county_simple/MapServer/0/query", and then you would define an "after" callback that loops through the returned features, and updates their render_Data values accordingly.

View solution in original post

3 Replies
Rhiannon
New Contributor II

I thought about this some more and came up with a more straightforward way of asking this question, and made an updated codepen.

Can you edit the values of attributes on a feature layer between this line of code:

const feature_layer = new FeatureLayer({
url: featureLayerURL,
outFields: ["*"]
});

and this line of code:

map.add(feature_layer);

So that features such as the ClassBreaksRenderer and PopupTemplate can use those updated values? 

(IE I want the ClassBreaksRenderer to break on the render_Data value, but I want to temporarily tweak that value before the map loads).

I don't want the attribute edits to be permanently applied to the source, I just want them to be used temporarily on the single load of the page/map.

https://codepen.io/rhip/pen/bGQqoQp

0 Kudos
JoelBennett
MVP Regular Contributor

The technical answer to the question in your second post is no.  In 3.x of the API, a FeatureLayer would immediately begin retrieving its service info as soon as you instantiate it, but in 4.x, it doesn't do so until after it's added to a View.  Therefore, since no features would have been retrieved between those two lines, there'd be nothing for you to update.

Fortunately, there are still multiple ways you could accomplish what you're trying to do, and one way in particular stands out above the rest because (1) your code shows you already have the external JSON data with county-to-rate information loaded before adding the layer to the map, and (2) your layer already has a predefined empty field waiting to hold the appropriate value (render_Data).  Your problem therefore is that you need to update that field after the application receives the FeatureLayer's data, but before the FeatureLayer processes it and renders it on the map.

The SDK provides the means to do exactly that with the RequestInterceptor.  To use a RequestInterceptor, you create one and add it to the "interceptors" property of the esri.config.request object.  The "urls" value of your interceptor would be "https://gis.mo.gov/arcgis01/rest/services/DMH/DMH_county_simple/MapServer/0/query", and then you would define an "after" callback that loops through the returned features, and updates their render_Data values accordingly.

Rhiannon
New Contributor II

Thank you so much! That worked perfectly, and I'm not sure I would have run across it on my own. You really saved me.

I made a final codepen to demonstrate it working in case someone finds this in the future with a similar question. 
https://codepen.io/rhip/pen/gOQmKeV