Cannot call member property on object of this type

2988
10
01-17-2022 05:37 AM
Labels (2)
DaveBodak
Occasional Contributor

Hello,

I am trying to reference data stored in another feature layer in ArcGIS Online for a pop-up, and there are a few other instances where I want to use the expressions to reference data stored in other feature layers. 

Here is the line of code that I am using to reference the data, in this case I am trying to get the inspection date from the hydrant inspections table:

return (FeatureSetByName($datastore,"Hydrant Inspections").InspectionDate)

When I do this, I receive the following error:

"Cannot call member property on object of this type."

I have tried a few different methods, such as going through the portal and setting the ID of the dataset, but I am still getting the same error message when I try to reference the field.

Thank you for any assistance!

0 Kudos
10 Replies
jcarlson
MVP Esteemed Contributor

A FeatureSet doesn't have attributes, it has Features. All you need is some way to grab an individual feature from the FeatureSet.

The simplest way to do that is with the First function. Once you get your feature, you can access its attributes the way you want.

Also, it can help keep your expression clear and easy to understand by using variables.

 

 

var fs = FeatureSetByName($datastore, "Hydrant Inspections")

var inspection = First(fs)

return inspection.InspectionDate

 

 

Which Feature?

When you grab the first feature in the set, how do you know which feature you're getting? And is it the one you want? Based on your post, I assume you want only inspections which apply to the hydrant you've clicked on. Additionally, if there are multiple inspections, you may only want the most recent.

To do that, we can include the functions Filter and OrderBy.

 

 

var fs = FeatureSetByName($datastore, "Hydrant Inspections")
var ID = $feature.hydrantID // just replace with your own field name as needed

// Get inspections for clicked hydrant
var filt_fs = Filter(fs, "hydrantID = @ID")

// Order inspections with most recent first
var ordered_fs = OrderBy(filt_fs, "InspectionDate DESC")

// Return most recent inspection specific to hydrant
var inspection = First(fs)

return inspection.InspectionDate

 

 

- Josh Carlson
Kendall County GIS
DaveBodak
Occasional Contributor

Thank you for your help, this makes sense to me. I implemented the code and do not receive any errors, but I do not get any information showing in the pop-up menu. I completed a mock inspection on this hydrant a few days ago for testing. Do you see any problems that stand out?

Thanks for your help!

0 Kudos
jcarlson
MVP Esteemed Contributor

Yes, I do! My mistake, actually. When you reference a variable in your filter expression, it needs to be exactly as it is established, so "OBJECTID = @ID" would be correct. I'll update my original response to reflect that.

Also, keep in mind that your inspection's objectid only refers to its row number in the table, and has no real relationship with the hydrants layer. It will still work as a filter, provided an objectid of the same value exists in both tables.

- Josh Carlson
Kendall County GIS
0 Kudos
jcarlson
MVP Esteemed Contributor

How strange! It forces my "@id" into upper case when I save the post. I've changed the post for ID to be upper case, but use whichever you like, so long as the filter expression matches the var name.

- Josh Carlson
Kendall County GIS
0 Kudos
DaveBodak
Occasional Contributor

Okay, I think the Object ID is the problem in this case. My Hydrant Inspections table does not contain an Object ID field, when I set this up I used a related table class with the Hydrant layer. 

I followed along with Eric's Inspection Workflow series to set up this inspection table and I created a "Recent Hydrant Inspections" feature layer the same way that he did in his, the last inspection date is stored in this feature layer. I have a field in my "Hydrants" feature layer that is "Last service date" and I would like to populate this field using the other feature layer.

I think this could be an alternate solution since I do not have the same Object ID in the table and feature layer. That being said, is there a way to make it so there is an Object ID field in my Hydrant Inspection Table that is identical to the hydrant being inspected.

I apologize for taking a bit of a turn on this, but your help is much appreciated!

Thanks!

0 Kudos
jcarlson
MVP Esteemed Contributor

There is a way to do that, but it really depends on your data structure. Adding a field to your inspections table is simple enough, and then whatever editor / app you are using to collect the data can insert a value into that field.

Besides the objectid, is there some unique identifier on your hydrants layer? Something an inventory number or code?

Alternatively, you might consider publishing a service that already has a relationship class in place that links the features to records in the table.

- Josh Carlson
Kendall County GIS
0 Kudos
DaveBodak
Occasional Contributor

There is a unique GlobalID for each hydrant in the layer, the ObjectID for each one is also unique but is not represented in the Hydrant Inspections table. Is there a way to use this to calculate the field within the hydrants layer from the hydrant inspection table?

Your idea of typing in the Object ID for each inspection could definitely work as long as there wouldn't be a mistyped number when filling out the inspection file.

There is a relationship class between the hydrant and hydrant inspections table, would this make it easier to pull the information into the field for the hydrant layer?

Thanks for your help!

0 Kudos
jcarlson
MVP Esteemed Contributor

If there's a relationship class, it's most often going from hydrant GlobalID → inspection GUID. Check your inspection table to see if there's a GUID field type. In such a case, you simply use the $feature.globalid as the filtering value, and the GUID field as the field on which to filter. In code, that would be:

var hydrant_id = $feature.globalid

var filt_fs = Filter(fs, "relate_GUID_field = @hydrant_id")

 

But that may be besides the point. If you're working with a relationship class, you ought to be able to access the related records directly, using the FeatureSetByRelationShipName function.

In case you don't know the relationship name off hand, you can find it in the expression builder at the bottom of the fields list:

jcarlson_0-1642513807677.png

Click "Related Records" and you can see the relationship there. Clicking the blue function will insert it into your expression.

jcarlson_1-1642513864057.png

The output of this FeatureSet function is equivalent to pulling in the featureset by name and then filtering it, but going through the relationship class, it performs a bit more efficiently.

- Josh Carlson
Kendall County GIS
0 Kudos
DaveBodak
Occasional Contributor

This makes sense and I think it is what I am looking for. Now, the only problem is that the expression is returning a null value, even when there was a completed inspection for the hydrant.

I wrote my expression as follows, referencing the last inspection date in the table:

FeatureSetByRelationshipName($feature,"InspectionDate")

I then added the expression to my pop-up for the hydrant layer:

Location: {LOCDESC}
Manufacturer: 
{MANUFACTURER}
Year: 
{HYDYEAR}
Hydrant ID: 
{OBJECTID}
Last Inspection Date: {expression/expr0}

 Here is the pop-up that is shown when I select this hydrant, the table along the bottom suggests that this hydrant does have a related inspection affiliated with it.

DaveBodak_2-1642515927401.png

For reference, here is the dialogue box from the "recent hydrant inspections" layer on the same hydrant where the last service date is directly saved, this layer was created by the "Join Features" analysis tool

DaveBodak_1-1642515205115.png

Thanks again!

0 Kudos