I have a situation where in I am having multiple on click events that are fired on a column header. There will be one event for filter dropdown and the other one for sorting. There is a filter icon , on click of which column filter options will be shown. And on click of the header, sorting should also happen.
Now whenever I click on the filter icon, both handlers are getting fired. Can someone help me with this.
On click of filter icon, only filter handler should fire
Help would be appreciated.
Sandbox: https://codesandbox.io/s/relaxed-feather-xrpkp
import * as React from "react";
import { render } from "react-dom";
import ReactTable from "react-table";
import "./styles.css";
import "react-table/react-table.css";
import Child from "./Child";
interface IState {
data: {}[];
columns: {}[];
}
interface IProps {}
export default class App extends React.Component<IProps, IState> {
constructor(props: any) {
super(props);
this.state = {
data: [
{ firstName: "Jack", status: "Submitted", age: "14" },
{ firstName: "Simon", status: "Pending", age: "15" },
{ firstName: "Pete", status: "Approved", age: "17" }
],
columns: []
};
}
handleColumnFilter = (value: any) => {
console.log(value);
};
sortHandler = () => {
console.log("sort handler");
};
componentDidMount() {
let columns = [
{
Header: () => (
<div onClick={this.sortHandler}>
<div style={{ position: "absolute", marginLeft: "10px" }}>
<Child handleFilter={this.handleColumnFilter} />
</div>
<span>First Name</span>
</div>
),
accessor: "firstName",
sortable: false,
show: true,
displayValue: " First Name"
},
{
Header: () => (
<div onClick={this.sortHandler}>
<span>Status</span>
</div>
),
accessor: "status",
sortable: false
}
];
this.setState({ columns });
}
render() {
const { data, columns } = this.state;
return (
<div>
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
className="-striped -highlight"
/>
</div>
);
}
}
const rootElement = document.getElementById("root");
render(<App />, rootElement);
import * as React from "react";
import { Icon } from "semantic-ui-react";
import "./styles.css";
interface IProps {
handleFilter(val1: any): void;
}
interface IState {
showList: boolean;
}
export default class Child extends React.Component<IProps, IState> {
constructor(props: any) {
super(props);
this.state = {
showList: false
};
}
toggleList = () => {
console.log("filter handler");
this.setState(prevState => ({ showList: !prevState.showList }));
};
render() {
let { showList } = this.state;
let visibleFlag: string;
if (showList === true) visibleFlag = "visible";
else visibleFlag = "";
return (
<div>
<div style={{ position: "absolute" }}>
<div
className={"ui scrolling dropdown column-settings " + visibleFlag}
>
<Icon className="filter" onClick={this.toggleList} />
</div>
</div>
</div>
);
}
}
You just need event.stopPropagation()
. This will isolate the event to only this specific execution-block. So now when you click on the filter-icon, it will only trigger the designated event-handler.
toggleList = (event) => {
event.stopPropgation()
console.log("filter handler");
this.setState(prevState => ({ showList: !prevState.showList }));
};
You'll also need to use it here as well:
handleValueChange = (event: React.FormEvent<HTMLInputElement>, data: any) => {
event.stopPropagation()
let updated: any;
if (data.checked) {
updated = [...this.state.selected, data.name];
} else {
updated = this.state.selected.filter(v => v !== data.name);
}
this.setState({ selected: updated });
};
And here:
passSelectionToParent = (event: any) => {
event.preventDefault();
event.stopPropagation()
this.props.handleFilter(this.props.name, this.state.selected);
};
Literally, anytime you have a click-event for a parent-markup and it has children mark-up that also have a click-event, you can use event.stopPropagation()
to stop the parent click-event from firing.
Here's the sandbox: https://codesandbox.io/s/elated-gauss-wgf3t