React to change in selection on data source from custom widget

226
2
08-16-2021 03:53 PM
AlejandroMari1
New Contributor III

Hello! I'm trying to understand how can I "listen" for changes on a data source selection on a custom widget that were made on a different widget.

I have a feature layer data source. From one custom widget, I get hold of that that source I select some features. 

From a different custom widget, I want to listen on that change so I can render information appropriately.

This is my render function:

render() {
    const { dataSource } = this.state;
    const useDataSource = this.props.useDataSources && this.props.useDataSources[0]
    let query: FeatureLayerQueryParams = {
        where: "1=1",
        returnGeometry: false,
        outFields: ["*"]
    };
    return (
        <div>
            <DataSourceComponent
                useDataSource={useDataSource}
                query={dataSource ? query : null}
                widgetId={this.props.widgetId}
                onDataSourceCreated={this.onDataSourceCreated}
                // onQueryStatusChange={this.onQueryStatusChange}
                onDataSourceInfoChange={this.onDataSourceInfoChange}
                onCreateDataSourceFailed={this.onCreateDataSourceFailed}
            >
                {this.renderTheSubComponent}
            </DataSourceComponent>
        </div>
    )
}
onDataSourceCreated = (dataSource: QueriableDataSource): void => {
    this.setState({ dataSource: dataSource });
}

None of the callbacks there are called when the selection is changed. ComponentDidUpdate also doesn't get called, so my component never receives the selection.

Other OOTB widgets (like the List widget) are properly reacting to selection changes, so I'm positive the selection is properly done.

Any help will be appreciated.

Alejandro

0 Kudos
2 Replies
KevinHibma-EsriCA
Esri Contributor

I can share how I've solved this, although I'll caution I'm not sure it's the best way.

I'm using a similar pattern to how you started with the DataSource:

      {<DataSourceComponent widgetId={this.props.id} useDataSource={this.props.useDataSources[0]}
          onDataSourceCreated={this.onDs} 
          onDataSourceInfoChange={this.dataChanged}
          queryCount>
        {this.layerHandler}
      </DataSourceComponent>}

 

onDataSourceInfoChange will be triggered when interacting with the data. I believe any widget you've setup within the Builder that listens for Selection change within the framework should trigger this. So a selection drawn in the map widget, or you could manually perform the selection on the datasource in your first widget code. Eg.

this.state.datasource.selectRecordById(oid)  //from the selecting widget, not the recieving widget

 

From the widget you want to react to the selection change....(the widget with the 1st datasource code above) ..... in my case I'm calling into dataChanged - See the 2 test cases I have here:

dataChanged = (info: IMDataSourceInfo) =>{
  console.log("imdatasource status", info)
  if (this.state.datasource){
    if (this.state.datasource.getStatus() == "LOADED"){
      let r = this.state.datasource.getSelectedRecords()
      console.log("SELECTED RECORDS:", r)
    }
  }
  if (info.selectedIds){
    console.log("info ids: ", info.selectedIds)
    this.selectedSite([info.selectedIds[0]])
  }
}

 

My selected records in the first branch always comes up with an empty array. (I point this out as I would have expected the datasource to have the selection here, but it doesn't. Thus why I'm cautioning this might not be the best way). However, within the second branch info.selectedIds - when there is a selection, I can get the OID of the feature from that.

Once you have the OID, simply carry on with what you're doing. In my case, I need to get more attributes from the selected feature:

selectedSite = (oid_facname) =>{

  const oid = oid_facname[0];
  //const fac_name = oid_facname[1];
  //const fac_id = oid_facname[2];

    if (this.state.datasource && this.state.datasource.getStatus() == "LOADED"){
      if (oid){
        this.state.datasource.selectRecordById(oid)      
        const fac_name = this.state.datasource.getRecords()[0].feature.attributes['facility_name_location'] 

 

Alternatively, you could broadcast the OID or attributes of your selected feature and have the 2nd widget listen for that. Check the widget communication help to see this pattern. I only offer this up as another idea, I don't know if it'd be suitable for your widgets....

0 Kudos
AlejandroMari1
New Contributor III

Thanks @KevinHibma-EsriCA for your detailed response. Much appreciated.

That works, in my code the onDataSourceInfoChange also gets called now whenever the data selection changes (I don't know why it wasn't before, something must have been wrong in my code).

I've also noticed is that the child component of the <DataSourceComponent> also gets triggered every time the selection changes.

Example:

updateChild = (ds?: QueriableDataSource, dsInfo?: IMDataSourceInfo) => {
    const selectedProjects = ds.getSelectedRecords(); // Will contain the selected records.
}

render() { 
	return (<div>
		{<DataSourceComponent widgetId={this.props.id} useDataSource={this.props.useDataSources[0]}
          onDataSourceCreated={this.onDs} 
          onDataSourceInfoChange={this.dataChanged}
          queryCount>
			{this.updateChild}
		}
      </DataSourceComponent>
	</div>)
}

 

0 Kudos