Hello,
I am developing a custom widget that interacts with a webMap in my organization. My experience is secured with a user group from my organization. My goal is to filter the data on my map according to the logged-in user.
At the moment, I am able to retrieve the authenticated user. However, I am encountering difficulties in using this information to apply a filter to the data displayed when the map opens.
Does anyone have any ideas or has anyone worked on this scenario before?
Solved! Go to Solution.
The user information can be accessed in a custom widget with the props.user object. So your filter could work something like this.
if (props.user.username === 'Bob') {
filterFunction()
}
For an example widget that uses the props.users object, you can look at the Security Widget.
Can you share more of your code? There isn't enough here to see why you can't connect to the dataSource.
Here is the official sample for filtering a feature layer using it's dataSource.
The problem line here looks like this one.
const dataSource = dataSourceId && DataSourceManager.getInstance().getDataSource(dataSourceId);
With the && operator, I think this line is only capable of returning a Boolean value. Try taking out the dataSourceId && part.
const dataSource = DataSourceManager.getInstance().getDataSource(dataSourceId);
You might also need to use a shouldComponetUpdate() function to handle the initial load where the dataSource may not be available yet.
https://www.geeksforgeeks.org/what-does-shouldcomponentupdate-do-and-why-is-it-important/#
The user information can be accessed in a custom widget with the props.user object. So your filter could work something like this.
if (props.user.username === 'Bob') {
filterFunction()
}
For an example widget that uses the props.users object, you can look at the Security Widget.
Thank you for your response and your promptness. The issue arises precisely when I try to apply the filter to the datasource :
if (this.props?.user?.username === "user1") {this.setState({query : "field = 'dispo'"})queryParams = {where: this.state.query};console.log(this.state.query);}}console.log(dataSource)dataSource?.updateQueryParams(queryParams, this.props.id);
Since it can't retrieve the datasource, it displays "undefined
Can you share more of your code? There isn't enough here to see why you can't connect to the dataSource.
Here is the official sample for filtering a feature layer using it's dataSource.
export default class Widget extends React.PureComponent<AllWidgetProps<unknown>,State> {
constructor(props){
super(props)
this.state={filtre: '1=1'}
this.state={user:'utilisateur'}
this.state={query:"field = '1=1'"}
}
}
componentDidMount() {
this.setState({ user: this.props.user?.username });
const dataSourceId = this.props.useDataSources?.[0]?.dataSourceId;
const dataSource = dataSourceId && DataSourceManager.getInstance().getDataSource(dataSourceId);
let queryParams;
if (this.props?.user?.username === "user1") {
this.setState({query : "field = 'OK'"})
queryParams = {
where: this.state.query
};
}
if (!dataSource) {
console.log("Failed to get dataSource");
} else {
dataSource?.updateQueryParams(queryParams, this.props.id);
}
}
render() {
return (
<div className="widget-starter jimu-widget">
</div>
)
The problem line here looks like this one.
const dataSource = dataSourceId && DataSourceManager.getInstance().getDataSource(dataSourceId);
With the && operator, I think this line is only capable of returning a Boolean value. Try taking out the dataSourceId && part.
const dataSource = DataSourceManager.getInstance().getDataSource(dataSourceId);
You might also need to use a shouldComponetUpdate() function to handle the initial load where the dataSource may not be available yet.
https://www.geeksforgeeks.org/what-does-shouldcomponentupdate-do-and-why-is-it-important/#
hi, Jeffrey, would you like to help? I have code as above, and it need to filter data source by props.user, I used esri github example filter layer, also took a look at your security widget. but it seem data sources do not work as expected during initial loading.
hi, any luck for solving this issue? I am doing exactly the same thing, but it seems data source is not available, or sometimes it becomes available, not sure how to wait it properly:
my widget.tsx, I put one text input with button, so I can click either by using props.user or test user, that way it always work, but for initial loading, just cannot get data source available most of time.
import { AllWidgetProps, jsx, FeatureLayerDataSource, SqlQueryParams, DataSourceManager } from 'jimu-core';
import { IMConfig } from '../config';
import { TextInput} from 'jimu-ui';
import React, { Component } from 'react';
interface State {
testInput: string;
unavailableDataSources: string[];
}
class Widget extends Component<AllWidgetProps<IMConfig>, State> {
constructor(props: AllWidgetProps<IMConfig>) {
super(props);
this.state = {
testInput: '',
unavailableDataSources: props.useDataSources ? props.useDataSources.asMutable().map(ds => ds.dataSourceId) : []
};
}
componentDidMount() {
this.retryFilterDataSources();
}
componentDidUpdate(prevProps: AllWidgetProps<IMConfig>) {
if (prevProps.useDataSources !== this.props.useDataSources || prevProps.user !== this.props.user) {
this.setState({
unavailableDataSources: this.props.useDataSources.asMutable().map(ds => ds.dataSourceId)
}, this.retryFilterDataSources);
}
}
retryFilterDataSources = (retries = 50, delay = 1000) => {
const dsManager = DataSourceManager.getInstance();
const { unavailableDataSources } = this.state;
const stillUnavailable = unavailableDataSources.filter(dsId => !dsManager.getDataSource(dsId));
if (stillUnavailable.length === 0) {
this.filterDataSources();
} else if (retries > 0) {
stillUnavailable.forEach((dsId, index) => {
const originalIndex = this.props.useDataSources.findIndex(ds => ds.dataSourceId === dsId);
console.warn(`Data source ${originalIndex + 1} of ${this.props.useDataSources.length}: ${dsId} not found.`);
});
console.log(`Retrying to check data sources... Attempts left: ${retries}`);
setTimeout(() => this.retryFilterDataSources(retries - 1, delay * 2), delay);
} else {
console.warn('Data sources not ready after multiple attempts.');
}
};
textInputChangeHandler = (evt: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ testInput: evt.target.value });
};
filterDataSources = () => {
if (this.props.useDataSources?.length > 0 && this.props.user) {
const dsManager = DataSourceManager.getInstance();
const username = this.props.user.username;
const clientName = username.split('_')[1];
console.log('Username:', username);
console.log('Client Name:', clientName);
console.log('Test Input:', this.state.testInput);
this.props.useDataSources.forEach((useDataSource, index) => {
const ds: FeatureLayerDataSource = dsManager.getDataSource(useDataSource.dataSourceId) as FeatureLayerDataSource;
if (!ds) {
console.warn(`Data source ${index + 1} of ${this.props.useDataSources.length}: ${useDataSource.dataSourceId} not found.`);
return;
}
let queryParams: SqlQueryParams;
if (this.state.testInput === '') {
const
clientName = this.props.user.username.split('_')[1];
queryParams = {
where: `LOWER(Client) LIKE LOWER('OWNER%')`
};
} else {
const testClientName = this.state.testInput.split('_')[1];
queryParams = {
where: `LOWER(Client) LIKE LOWER('${testClientName}%')`
};
}
console.log(`Query Params for data source ${index + 1} of ${this.props.useDataSources.length}:`, queryParams);
ds.updateQueryParams(queryParams, this.props.id);
});
} else {
console.warn('No data sources available to filter.');
}
};
render() {
return (
<div className="widget-get-map-coordinates jimu-widget p-2">
<p>
<TextInput
placeholder='Filter by username'
onChange={this.textInputChangeHandler}
value={this.state.testInput}
/>
<button onClick={this.filterDataSources} style={{ marginLeft: '10px' }}>
Test Filter
</button>
</p>
</div>
);
}
}
export default Widget;