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.
Related
In my new project, I am using material UI autocomplete within tabs, and using useImmer hooks for state management. Values in the autocomplete are populated through map function and everything works properly. However, the dropdown functionality is not working after switching the Tabs.
The values are reaching to this component as
const Dropdownlist = ({ defaultRates, value, onChange, index }) => {
return (
<Autocomplete
{...defaultRates}
size="small"
inputValue={value}
value={value}
autoSelect={true}
clearOnEscape={true}
onChange={(event, newValue) => {
onChange( newValue, index );
}}
renderInput={(params) => <TextField {...params} />}
/>
);
};
export default Dropdownlist;
Values of 'defaultRates' was built using
const ratings =
Rates.map((charge) => {
return ({ id: charge.rateid, label: charge.rate });
});
const defaultRates = {
options: ratings,
getOptionLabel: (option) => option.label,
};
Then,
const Rates = [
{
rateid: 101,
rate:"10"
},
{
rateid: 102,
rate:"30"
},
{
rateid: 103,
rate:"1"
},
{
rateid: 104,
rate:"2"
},
];
export default Rates;
Finally, On Change functionality
const onChange = (e,i) => {
let newState;
if(e)
{
const { id, label } = e;
newState = transactions.map((item, index) => {
var tds = (label/100)*item.amount;
if (index === i) {
return {
id: item.id,
transaction: item.transaction,
amount: item.amount,
name: item.name,
type: item.type,
ts:item.ts,
tr:label,
tds: tds,
error:false,
};
} else {
return item;
}
});
setTransactions(newState);
}
}
In the first tab I have many autocomplete dropdown and the selected values are also using in the second tab. If I switch to Tab2 and return back to Tab1, I can see the selected values there. But If I want to change the selected value, nothing happens while clicking the dropdown icon. Please let me know if anyone ever experienced in this context. Would like to know if I using Material UI autocomplete parameters in the right way?
I have gone through Material UI documentation and Autocomplete params. Please advise if it is a state management issue or Mat UI bug?
I am using React semantic ui. I am rendering a dropdown in Fieldset. I have written code such that, once a option is selected, the options is updated such that the selected option is removed from the list. But when I select an option from the dropdown, the selected value is not displayed, rather it shows empty.
Here is my code:
This is my dropdown code:
<Dropdown
name={`rows.${index}.mainField`}
className={"dropdown fieldDropdown"}
widths={2}
placeholder="Field"
fluid
selection
options={mainFieldOptions}
value={row.mainField}
onChange={(e, { value }) => {
setFieldValue(`rows.${index}.mainField`, value)
updateDropDownOptions(value)
}
}
/>
My options:
let mainField = [
{ key: "org", text: "org", value: "org" },
{ key: "role", text: "role", value: "role" },
{ key: "emailId", text: "emailId", value: "emailId" },
]
Also, I have:
const [mainFieldOptions, setMainFieldOptions] = useState(mainField)
And,
const updateDropDownOptions = (value:any) => {
let updatedOptions: { key: string; text: string; value: string }[] = []
mainFieldOptions.forEach(option => {
if(option.key != value){
updatedOptions.push({ key:option.key , text:option.key, value:option.key })
}
})
setMainFieldOptions(updatedOptions)
console.log("mainfield", mainField)
}
In onChange, if I dont call updateDropDownOptions() method, the dropdown value is set. But when I call the method, its giving blank value. Please help.
There are few changes required in your code,
You are pushing the entire initialValues when you are adding a row which is an [{}] but you need to push only {} so change your code to initialValues[0] in your push method.
Its not needed to maintain a additional state for the options. You can filter the options based on the selected option in other rows which is available in the values.rows .
Util for filtering the options
const getMainFieldOptions = (rows, index) => {
const selectedOptions = rows.filter((row, rowIndex) => rowIndex !== index);
const filteredOptions = mainField.filter(mainFieldOption => !selectedOptions.find(selectedOption => mainFieldOption.value === selectedOption.mainField));
return filteredOptions;
}
Call this util when rendering each row
values.rows.length > 0 &&
values.rows.map((row, index) => {
const mainFieldOptions = getMainFieldOptions(values.rows, index);
Working Sandbox
I have a data table with users and I want to make a delete button work on the rows, but it seems that it cannot be done by reactish means.
The DataGrid is used like this:
<DataGrid
rows={users}
columns={columns}
pageSize={5}
checkboxSelection
/>
I have a column with custom renderCell function that shows some action buttons. The column definition is this:
{
field: "actions",
headerName: "",
width: 120,
type: "",
sortable: false,
renderCell: (
params: GridCellParams
): React.ReactElement<any, string | React.JSXElementConstructor<any>> => {
return (
<UserRowActions
userId={params.getValue(params.id, "id")?.toString()!}
/>
);
}
}
The params object offers a few properties but I do not know how to do something like this: delete the row on which a button was clicked, a button that is defined in the UserRowActions component.
I would also like to find whether it is not possible to do this using the MUI DataGrid component as it is today.
I don't know what to do since the API does not look reactish to me right now.
I use:
"#material-ui/core": "^4.12.1",
"#material-ui/data-grid": "^4.0.0-alpha.30",
"react": "^16.14.0",
I made a context specially for the data grid action buttons:
export const DataGridContext = React.createContext<{ deleteUser?: (uid: string) => void }>({});
// ...
const { data: users, isLoading, isError } = useGetUsersQuery();
const [usersRows, setUsersRows] = useState<IUser[]>([]);
useEffect(() => {
if (typeof users !== 'undefined') {
setUsersRows(users);
}
}, [users]);
<DataGridContext.Provider value={{ deleteUser: (uid: string) => {
const newRows = [...usersRows];
const idx = newRows.findIndex(u => u.id === uid);
if (idx > -1) {
newRows.splice(idx, 1);
setUsersRows(newRows);
}
}}}>
<DataGrid
rows={usersRows} // ...
/>
</DataGridContext.Provider>
// In the UserRowActions component:
const dataGrid = useContext(DataGridContext);
// ...
dataGrid.deleteUser!(userId);
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)
I have a table that implements react-bootstrap-table2. They provide a custom way of doing external filter (out of the column header). In my table, the first column is a combination of data that I pass a string with # as separator and the format them with the formatter function as follow:
This is my column definition:
let projectFilter;
columns = [{
dataField: 'project',
text: 'Project',
filter: textFilter({
options: fpsoOptions,
getFilter(filter){
projectFilter = filter;
},
style: { display: 'none' }
}),
sort: true,
formatter: this.projectFormatter,
headerStyle: (col, idx) => {
return smHeaderStyle;
},
}, [..]
And this is the projectFormatter function:
projectFormatter = (cell, row) => {
const values = cell.split('|');
const fpsos = values[0].split('#');
return (
<div>
{fpsos.map((pu, idx) => {
const identity = pu.split(';')[0];
const id = pu.split(';')[1];
const separator = idx !== fpsos.length - 1 ? ", " : '';
return (
<Link to={`/view/${id}/fpso`}>{identity}{separator}</Link>
)
})}
<br/>
<span><b>{ values[1] }</b></span><br/>
</div>
);
}
The filtering works fine when it is a text input filter. Now, I'm trying to do a custom select filter with a LIKE operator behaviour, which the selected value in the dropdown (fpso list) would be filtered as a substring of this column.
This is my onChange function that triggers the table filter, as shown in the documentation here. But I'm not sure how to get the like behaviour.
const onChangeFilter = (e) => {
projectFilter(e.target.value)
}
I appreciate any clue/help. Thanks in advance