AG Grid, Capture the event on click of chevron - reactjs

Ag-grid provides onCellClicked event for when a cell is clicked. But I noticed that it doesn't trigger when we click the chevron. I need to capture this event for analytics as a user might click the chevron directly rather than the cell itself. Any idea how to achieve this or what event to use here? I am using detailRenderer to render child rows, if that helps. Here is one of the columnDefs item:
{
headerName: "Line Item",
field: "displayLineNumber",
width: "100px",
sortable: false,
expandable: true,
onCellClicked: (event) => {
event.node.setExpanded(!event.node.expanded);
if (event.node.expanded === true) {
DataLayerUtils.pushEvent(
"click",
{
name: "Open Line Item",
type: "button",
},
{
click: {
category: "Quote Detail Table Interactions",
},
}
);
} else {
DataLayerUtils.pushEvent(
"click",
{
name: "Collapse Line Item",
type: "button",
},
{
click: {
category: "Quote Detail Table Interactions",
},
}
);
}
},
rowClass: ({ node, data }) => {
return `cmp-product-lines-grid__row ${
!data?.children || data.children.length === 0
? "cmp-product-lines-grid__row--notExpandable"
: ""
}`;
},
detailRenderer: ({ data }) => (
<section className="cmp-product-lines-grid__row cmp-product-lines-grid__row--expanded">
<ProductLinesChildGrid
gridProps={gridProps}
license={gridProps.agGridLicenseKey}
columnDefiniton={
whiteLabelMode ? whiteLabelCols() : quoteDetailsCols()
}
data={data.children}
onModelUpdateFinished={() => {
markupChanged(mutableGridData);
}}
/>
</section>
),
},

There's two ways to achieve this:
Implement the Grid Event rowGroupOpened (see: https://www.ag-grid.com/react-data-grid/grid-events/#reference-rowGrouping-rowGroupOpened)
This will be triggered whenever the user opens a group node.
onRowGroupOpened={(params) =>
console.log('onRowGroupOpened', params.expanded)
}
Implement the Grid Event cellMouseDown (see: https://www.ag-grid.com/react-data-grid/grid-events/#reference-selection-cellMouseDown) to capture the chevron click event.
This will be triggered only when the user clicks the expand chevron
onCellMouseDown={(params) => {
const isMasterRowGroupExpanded = params.event.target.classList.contains(
'ag-icon-tree-closed'
);
if (isMasterRowGroupExpanded) {
console.log('onCellMouseDown', params.value);
}
}}
See both of these approaches implemented in the following plunkr.

Related

Navigation in DetailsList not possible with Monaco editor

Hi I'm using the DetailsList and I want to be able to move my selection from column to column using tab.
But I came across this issue on Github:
https://github.com/microsoft/fluentui/issues/4690
Arrow keys needs to be used to navigate across the list but unfortunately I'm using a Monaco Editor in the list and the arrow key is blocked inside the Editor...
I would like to know if there is way to disable the List to set the TabIndex to -1
or
if Monaco can release the arrow key when the cursor is at the end of the text (Like a textbox).
I got something working following this rationale:
listen to the onKeydown event on monaco editor
identify the position of the caret
know the total of lines
get the string of a specific line
move the focus out from monaco editor
Knowing these then you can check if the caret is at the end of the last line and move the focus when the user press the right arrow key. I also added the code to check when the caret is at the very beginning and move the focus to the cell to the left.
This is the code I ended up with
import * as React from "react";
import "./styles.css";
import { DetailsList, IColumn } from "#fluentui/react";
import MonacoEditor from "react-monaco-editor";
export default function App() {
const columns: IColumn[] = [
{
key: "name",
minWidth: 50,
maxWidth: 50,
name: "Name",
onRender: (item, index) => (
<input id={`name-row-${index}`} value={item.name} />
)
},
{
key: "type",
minWidth: 200,
name: "Type",
onRender: (item, index) => {
return (
<MonacoEditor
editorDidMount={(editor, monaco) => {
editor.onKeyDown((event) => {
if (event.code === "ArrowRight") {
const { column, lineNumber } = editor.getPosition();
const model = editor.getModel();
if (lineNumber === model?.getLineCount()) {
const lastString = model?.getLineContent(lineNumber);
if (column > lastString?.length) {
const nextInput = document.getElementById(
`default-value-row-${index}`
);
(nextInput as HTMLInputElement).focus();
}
}
}
if (event.code === "ArrowLeft") {
const { column, lineNumber } = editor.getPosition();
if (lineNumber === 1 && column === 1) {
const previousInput = document.getElementById(
`name-row-${index}`
);
(previousInput as HTMLInputElement).focus();
}
}
});
}}
value={item.type}
/>
);
}
},
{
key: "defaultValue",
minWidth: 100,
name: "Default Value",
onRender: (item, index) => (
<input id={`default-value-row-${index}`} value={item.defaultValue} />
)
}
];
const items = [{ name: "name", type: "type", defaultValue: "name" }];
return <DetailsList columns={columns} items={items} />;
}
You can see it working in this codesandbox https://codesandbox.io/s/wild-smoke-vy61m?file=/src/App.tsx
monaco-editor seems to be something quite complex, probably you'll have to improve this code in order to support other interactions (ex: I don't know if this works when code is folded)

Material-Table: Change a specific action's colour on click / state change

How can I style a particular MT action based on a different state?
Currently I'm doing something like this:
actions={[
rowData => {
const active = rowData && selected && rowData.tableData.id === selected.tableData.id;
return {
icon: 'bug_report',
iconProps: { color: active ? 'secondary' : 'primary' },
onClick: (event, info) => {
setSelected(info);
},
};
},
]}
However, instead of colouring the single selected element, it just stays as primary and does nothing. Why? Is it because the actions is rendered for action row and the next row !== selected?
So based on what I understood, I followed your code and ended up with this:
actions={[
rowData => {
let active =
rowData &&
clickedRow &&
rowData.tableData.id === clickedRow.tableData.id;
return {
icon: "bug_report",
tooltip: "Report bug",
onClick: (event, rowData) => setClicked(rowData),
iconProps: { color: active ? "primary" : "secondary" }
};
}
]}
Here is the sandbox.
I hope this is what you were looking for, if not, I believe that the examples at the official docs on Selection feature may help you with this kind of behaviour.
good luck!

Fluent UI dropdown selection

I am using fluent ui dropdown So, when i click on dropdown the first option is selected by default without selecting. If i click on dropdown and without selecting if i click somewhere on the page nothing should be selected and dropdown should be closed is what i want. Please help me with this.
Below is the code which iam using:
<Dropdown
disabled={this.state.HideLocationFilter}
selectedKey={selectedItem1 ? selectedItem1.key : undefined}
onChange={this._onChange1}
placeholder="Location"
options={[
{ key: 'UK', text: 'UK' },
{ key: 'Hyderabad', text: 'Hyderabad' },
{ key: 'Bangalore', text: 'Bangalore' },
{ key: 'Ahmedabad', text: 'Ahmedabad' },
{ key: 'Pune', text: 'Pune' },
{ key: 'Mumbai', text: 'Mumbai' },
{ key: 'USA', text: 'USA' }
]}
styles={dropdownStyles}
/>
private _onChange1 = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption): void => {
console.log(`Selection change: ${item.text} ${item.selected ? 'selected' : 'unselected'}`);
if(item.selected == true)
{
this.setState({ selectedItem1: item });
}
};
Initially it is like this:location dropdown
When i click on dropdown it is selecting by default(find picture of the same):dropdown when clicked
There is an issue currently that when you press on the default option and click outside of the browser window and then click back in the dropdown selects the first option.
The solution for this is to looked at the type of event and short circuit the onChange if the type === 'focus':
const onChange = useCallback((e, value) => {
if (e.type === 'focus') return
// do if not type 'focus'
}, [])
In my situation I needed also to trigger a re-render and augmented the above as such:
const onChange = useCallback((callback) => (e, value) => {
if (e.type === 'focus') return callback()
// do if not type 'focus'
}, [])
Then when calling it:
<Dropdown
{...props}
onChange={onChange(() => setOnChangeTriggered(true))}
/>

Change xAxis label style on data series click, Highcharts/React

I am trying to achieve a behavior in simple column chart in React, where I can click on series point and have xAxis label change style. Also, when you click again, that style should be removed. It is the same behavior as we have for mouse over and mouse out but for click event. I can get it to work with mouse events, but not click event.
Is this possible to achieve? This is a code sample I have.
Do the following:
Maintain a state say current update its value with the current axis number upon onClick
Define x-Axis and labels in your config-options
Use formatter function inside label. This function provides current axis value as argument. use it and compare it with your current state and adjust the style dynamically.
Working copy of code sample is here
Code Snippet
class App extends React.Component {
state = {
current: "black"
};
options = {
tooltip: {
enabled: false
},
xAxis: {
labels: {
formatter: item => {
const color = this.state.current === item.value ? "red" : "black";
const fontWeight =
this.state.current === item.value ? "bold" : "normal";
return `<span style="color: ${color}; font-weight: ${fontWeight}">${
item.value
}</span>`;
}
}
},
series: [
{
data: [1, 2, 3, 4],
type: "column",
colors: ["#000000"],
cursor: "pointer",
point: {
events: {
click: (e, x, y) => {
this.setState({ current: e.point.x });
console.log(e.target, e.point.x);
}
// mouseOver: function(e) {
// $(this.series.chart.xAxis[0].labelGroup.element.childNodes[this.x]).css({fontWeight: 'bold'});
// },
// mouseOut: function() {
// $(this.series.chart.xAxis[0].labelGroup.element.childNodes[this.x]).css({fontWeight: 'normal'});
// }
}
}
}
]
};
render() {
return (
<div>
<h2>Highcharts</h2>
<ReactHighcharts config={this.options} />
</div>
);
}
}
Just use the click event function to change the label CSS style. For example:
series: [{
...,
point: {
events: {
click: function() {
var ticks = this.series.xAxis.ticks,
label,
fontWeight;
if (ticks[this.x]) {
label = ticks[this.x].label;
fontWeight = (
label.styles.fontWeight && label.styles.fontWeight === 'bold'
) ? 'normal' : 'bold';
ticks[this.x].label.css({
'fontWeight': fontWeight
});
}
}
}
}
}]
Live demo: http://jsfiddle.net/BlackLabel/6m4e8x0y/4991/
API Reference:
https://api.highcharts.com/highcharts/series.column.events.click
https://api.highcharts.com/class-reference/Highcharts.SVGElement#css

How to select text to copy without triggering click event in reactjs

I am using react-table. I have defined onRowClick() function for a column. Here select text should highlight the text and clicking have to redirect to another page. Now when I try to select the text, its getting redirected. How to select text without triggering click event?
Following is my onRowClick function:
onRowClick = (state, rowInfo, columnInfo) => {
return {
onClick: (e, handleOriginal) => {
if (columnInfo.id) {
this.props.history.push(`/downloads/${rowInfo.original.id}`);
} else if (handleOriginal) {
handleOriginal();
}
}
};
}
The following is my react-table component:
<ReactTable
manual
getTdProps = {this.onRowClick}
data = {results}
onFetchData = {this.onFetchData}
sortable = {false}
showPagination = {false}
noDataText = 'no data found'
columns = {[
{
Header: 'Id',
maxWidth: 50,
accessor: "id",
Cell: (props) => <span className="btn-link pointer">{props.value} </span>
},
{
Header: 'Processed on',
maxWidth: 165,
accessor: "created_at",
Cell: (props) => <span> {this.getDateTime(props.value)} </span>
}
]
/>
Clicking on id column should redirect to the details page. Selecting text should select the id text.
I think onclick cannot be prevented but your desired result can be obtained by using Window.getSelection() method.
The Window.getSelection() method returns a Selection object representing the range of text selected by the user or the current position of the caret.
By using this method you can get the selected text and then you can calculate its length as:
window.getSelection().toString()
And then you can modify your onRowClick method as given below:
onRowClick = (state, rowInfo, columnInfo) => {
return {
onClick: (e, handleOriginal) => {
let selection = window.getSelection().toString();
if(selection.length <= 0) {
if (columnInfo.id && selection.length > 0) {
console.log("columnInfo.id", columnInfo.id);
this.props.history.push(`/downloads/${rowInfo.original.id}`);
} else if (handleOriginal) {
handleOriginal();
console.log("columnInfo.id", "nothing");
}
}
}
};
};
I have created a working demo.

Resources