Grommet DataTable Only allow Single select - reactjs

Does Grommet have a built in solution to only allow single or multiple selections within a dataTable? I came up with this useState function that clears the array before setting it but it has an adverse reaction of forcing the user to click twice. If array > 1 user clicks which sets the select array to [] forcing the user to click again.
import React from "react";
import ReactDOM from "react-dom";
import {Grommet, DataTable, Text, Meter, Box} from 'grommet';
const GridExample = () => {
const [select, setSelect] = React.useState([])
function handleRowSelect(selection) {
console.log(`You picked ${selection}`);
if (selection.length > 1) {
setSelect(selection[selection.length - 1].toArray)
} else {
setSelect(selection)
}
}
return (
<Grommet>
<DataTable
select={select}
onSelect={handleRowSelect}
columns={[
{
property: 'name',
search: true,
header: <Text>Name</Text>,
primary: true,
},
{
property: 'percent',
search: true,
header: 'Complete',
render: datum => (
<Box pad={{vertical: 'xsmall'}}>
<Meter
values={[{value: datum.percent}]}
thickness="small"
size="small"
/>
</Box>
),
},
]}
data={[
{name: 'Alan', percent: 20},
{name: 'Bryan', percent: 30},
{name: 'Chris', percent: 40},
{name: 'Eric', percent: 80},
]}
/>
<Text>Selected: {select}</Text>
</Grommet>
)
}
export default GridExample;
ReactDOM.render(
<GridExample/>,
document.getElementById("root")
);
Update: Using Slice in the function fixes the double click.
function handleRowSelect(selection) {
if (selection.length > 1) {
setSelect(selection.slice(-1))
} else {
setSelect(selection)
}
}

I don't think there is a built-in solution (for grommet 2.17.5).
Though, you can always try to manipulate select and onSelect in different ways, for example, one way for that will be to add a condition to onSelect and disable selection option once one row had been selected already:
onSelect={select.length < 1 && handleRowSelect}
This will make sure only one row is selected at any given point.
If you'd like the users to be able to reset their decision, you can always add a reset button that clears the array of selection, and the checkboxes will be enabled again.

Related

Fluent-UI's dropdown and combobox both not working

I have a React app with Fluent-UI 8 set up using npm install #fluentui/react according to the documents from Microsoft.
When I try their combobox or dropdown components, the dropdown list doesn't appear when clicked on it. I use their examples from the docs, which compiles without errors. But none of their examples work out of the box, and no other information is provided.
The problem is that the dropdown list does not appear when clicked on. Not in Edge, not in Firefox. When I check the elements on the page, I do not see the html elements with the list items, although I can cycle through them with the arrow keys. The list appears from the side when the window is tablet format, and setting ResponsiveMode did nothing. Whith a normal screen however, nothing is displaying, and no onchange events are fired.
This is my code for the dropdown:
import { IStackTokens, ResponsiveMode, Stack } from '#fluentui/react';
import { Dropdown, DropdownMenuItemType, IDropdownOption, IDropdownStyles } from '#fluentui/react/lib/Dropdown';
const dropdownStyles: Partial<IDropdownStyles> = { dropdown: { width: 300 } };
const DropdownControlledMultiExampleOptions = [
{ key: 'fruitsHeader', text: 'Spooler status', itemType: DropdownMenuItemType.Header },
{ key: 'apple', text: 'Apple' },
{ key: 'banana', text: 'Banana' },
{ key: 'grape', text: 'Grape' },
{ key: 'broccoli', text: 'Broccoli' },
{ key: 'carrot', text: 'Carrot' },
{ key: 'lettuce', text: 'Lettuce' },
];
export const DropdownList: React.FunctionComponent = () => {
const stackTokens: IStackTokens = { childrenGap: 20 };
return (
<Stack tokens={stackTokens}>
<Dropdown
placeholder="Select an option"
label="Disabled responsive"
options={DropdownControlledMultiExampleOptions}
styles={dropdownStyles}
responsiveMode={ResponsiveMode.unknown}
/>
<Dropdown
placeholder="Select an option"
label="Responsive with panel"
options={DropdownControlledMultiExampleOptions}
styles={dropdownStyles}
/>
</Stack>
);
};
Which I load in my app.tsx
function App() {
return (
<div className="App">
<DropdownList/>
</div>
);
}
Does anyone have an idea how I can get this to work? Or what is causing this?
EDIT and possible solution: It seems that removing the <React.Strict> tags in index.tsx does the job. Don't know why, but then the Fluid-UI controls work fine.

AntD Tree: need help! can't pass react element as icon OR title for antd tree

I'm using the AntD tree and I have a react element that I want to pass as either an icon or a title because it has custom styling. Due to it being IP I can't share too much code, but my question is:
how can I pass a react element (see below i.e. generic name) as either a title or icon and have antD tree render it?
i.e. this is what I want to pass as a prop to the icon or title
import React from 'react';
const genericName = (props) => {
// code uses props to get some infor for Color
// cant share code due to proprietary reasons
// but it is not needed for this question
const colorHTML = getColor(Color);
return (
<div>
<div className={`colors from`}>${colorHTML}</div>
{pin}
</div>
);
};
export default genericName;
in my console you can see node.icon is a typeof react.element. I want to target that and just pass the prop into antD tree as either title or icon
i.e.
return (
<Tree
icon={node.icon}
/>
)
I've searched and similar answers were given before antD forbid the use of children and strictly allows treeData. All examples I see only use strings in titles/icons, but since antD documentation is very limited, I need to know if my use case is possible. Right now, for the life of me I can't understand why it doesn't populate.
Thank you in advance.
It should definitely work to put a JSX component as title within treeData. Take a look at this snippet, I added a Icon here in one of the titles:
import React from 'react'
import { RightCircleOutlined } from '#ant-design/icons'
type Props = {}
import { Tree } from 'antd';
import type { DataNode, TreeProps } from 'antd/es/tree';
const treeData: DataNode[] = [
{
title: <span>{<RightCircleOutlined />} parent</span>, //icon added here
key: '0-0',
children: [
{
title: 'parent 1-0',
key: '0-0-0',
disabled: true,
children: [
{
title: 'leaf',
key: '0-0-0-0',
disableCheckbox: true,
},
{
title: 'leaf',
key: '0-0-0-1',
},
],
},
{
title: 'parent 1-1',
key: '0-0-1',
children: [{ title: <span style={{ color: '#1890ff' }}>sss</span>, key: '0-0-1-0' }],
},
],
},
];
const Demo: React.FC = () => {
const onSelect: TreeProps['onSelect'] = (selectedKeys, info) => {
console.log('selected', selectedKeys, info);
};
const onCheck: TreeProps['onCheck'] = (checkedKeys, info) => {
console.log('onCheck', checkedKeys, info);
};
return (
<Tree
checkable
defaultExpandedKeys={['0-0-0', '0-0-1']}
defaultSelectedKeys={['0-0-0', '0-0-1']}
defaultCheckedKeys={['0-0-0', '0-0-1']}
onSelect={onSelect}
onCheck={onCheck}
treeData={treeData}
/>
);
};
export default Demo;

Access selected value from react's Select Component

Hello dear community,
I want to create a very basic website for my school assignment.
I have a dropdown menu with a Select Component as its implementation. I need to access the selected value, which is a currency in my case, in order to update the information displayed on the page once a currency has been selected.
I am kind of frustrated since I wasn't able to find a helpfull solution to my relatively basic problem (I think it's basic :D)
My component class here:
import { Component } from "react";
import Select from 'react-select';
interface DropdownMenuProps {
values: [{}]
defaultValue: string
}
interface DropdownMenuState { }
/**
* Represents a Dropdown Menu
*/
export default class DropdownMenu extends Component<DropdownMenuProps, DropdownMenuState> {
render() {
return (
<div style={{ width: '120px' }}>
<Select id="dropdown-menu"
placeholder={this.props.defaultValue}
options={this.props.values}
// getOptionValue={(option) => option.value}
// getOptionLabel={(option) => option.label}
/>
</div>
)
}
}
This is how I create a dropdown menu compent:
<DropdownMenu defaultValue="Currency" values={[{ label: "EUR", value: "EUR" }, { label: "GBP", value: "GBP" }, { label: "USD", value: "USD" }]} ></DropdownMenu>
I'm glad for any tips :)
You have to use the onChange prop of react-select:
<select
id="dropdown-menu"
onChange={handleSelectChange}
>
and in this function you could handle the changes:
const handleSelectChange = (selectedVal) => console.log(selectedVal)
I recommend you using directly onChange and save it into a state:
1st:
Create state with the name you want:
const [selectValue, setSelectValue] = useState({});
2nd: Create options:
const options = [
{ label: "Tomate", value: 1 },
{ label: "Queso", value: 2 }
];
3rd: add method onChange in select and pass options:
const onChange = (ev) => {
setSelectValue(ev);
//console.log(ev);
console.log(selectValue);
};
<Select
id="dropdown-menu"
placeholder={"e"}
options={options}
onChange={onChange}
/>
I have created demo here:
https://codesandbox.io/s/ancient-pond-96h53?file=/src/App.js

How to format value of the React Select

I use "react final forms" and "react select".
I've organized an interface and functionality works, but I have one thing which I don't like.
React select requires options in next format:
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' }
]
and the value also should be set as { value: 'chocolate', label: 'Chocolate' }.
But for me is strange to have in my model of data (and send to the server also) the value like this - { value: 'chocolate', label: 'Chocolate' }, because I need only 'chocolate'.
Easy way is format the object into a single value after the form will be saved and format back from single value to the object before the rendering of the element. I know how to do it outside of form, but in this case I should solve this problem again and again for each select element separately.
What I would like to do:
Find a way how to set value of the react select as single value, like 'chocolate' instead of object.
OR
Create a wrapper for react select component and format value there when it sets (it's easy) and when the form get the value from this field (this I don't know how to do).
I will appreciate any help.
Method 1
With strings:
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Select from "react-select";
const data = ["1", "2"];
function SingleStringReactSelect() {
const [option, setOption] = useState();
return (
<section>
<Select
onChange={option => setOption(option)}
value={[option]}
getOptionLabel={label => label}
getOptionValue={value => value}
closeMenuOSelect={false}
options={data}
/>
</section>
);
}
Method 2:
Created example:
https://codesandbox.io/s/react-codesandboxer-example-z57ke
You can use map in options and with Wrapper like SingleValueReactSelect
import React, { Fragment, useState } from "react";
import Select from "react-select";
const data = ["chocolate", "strawberry", "vanilla"];
export function SingleValueReactSelect(props) {
const [selectedItem, setSelectedItem] = useState();
return (
<Select
{...props}
value={selectedItem}
onChange={item => {
setSelectedItem(item);
props.onChange(item.value);
}}
options={props.options.map(item => ({ label: item, value: item }))}
/>
);
}
export default function AppDemo() {
return (
<Fragment>
<p>SingleValueReactSelect Demo</p>
<SingleValueReactSelect
isClearable
isSearchable
options={data}
onChange={item => {
alert(item);
}}
/>
</Fragment>
);
}
You can transform/filter the object data once you are sending the form data to server or another component.
Setting the value of the react-select as a single value will not show it as selected in the React-Select.

Using react-datepicker in react-data-grid compoent

I am using react-data-grid component. It provides a grid structure with edit and lot more options. When we click on each cell, we are able to edit the content of the cell. In my project, I have a situation like when the date column is focused I want to bind a UI where the user can able to select the date.for that, I have used react-datepicker component. I am able to give react-datepicker component as a formatter in the date column option. I can able to change the date in the react datepicker component, but that is not updating the cell value (when you click on the console data button you can able to see the changes have been updated or not).so guys help me how I can update the cell value when a different date is selected in the react-datepicker component. It happening automatically when the value is changed in other cells.
import React from 'react';
import ReactDOM from 'react-dom';
import ReactDataGrid from 'react-data-grid';
import DatePicker from 'react-datepicker';
import moment from 'moment';
//helper to generate a random date
function randomDate(start, end) {
return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())).toLocaleDateString();
}
//helper to create a fixed number of rows
function createRows(numberOfRows){
var _rows = [];
for (var i = 1; i < numberOfRows; i++) {
_rows.push({
id: i,
task: 'Task ' + i,
startDate: randomDate(new Date(2015, 3, 1), new Date())
});
}
return _rows;
}
//function to retrieve a row for a given index
var rowGetter = function(i){
return _rows[i];
};
//renders react datepicker component
var ExampleDate = React.createClass({
displayName: 'Example',
getInitialState: function() {
return {
startDate:moment(this.props.value,"MM-DD-YYYY")
};
},
consoleDate:function(){
console.log(this.state.startDate);
},
handleChange: function(date) {
this.setState({
startDate: date
});
},
render: function() {
return (
<div>
<DatePicker selected={this.state.startDate} onChange={this.handleChange} />
</div>
);
}
});
//Columns definition
var columns = [
{
key: 'id',
name: 'ID',
width: 80
},
{
key: 'task',
name: 'Title',
editable : true,
width:100
},
{
key: 'startDate',
name: 'Start Date',
editable : true,
formatter:<ExampleDate />,
width:100
}
]
var Example = React.createClass({
getInitialState : function(){
return {rows : createRows(5)}
},
rowGetter : function(rowIdx){
return this.state.rows[rowIdx]
},
handleRowUpdated : function(e){
//merge updated row with current row and rerender by setting state
var rows = this.state.rows;
Object.assign(rows[e.rowIdx], e.updated);
this.setState({rows:rows});
},
output:function(){
console.log(this.state.rows);
},
render:function(){
return(
<div>
<ReactDataGrid
enableCellSelect={true}
columns={columns}
rowGetter={this.rowGetter}
rowsCount={this.state.rows.length}
minHeight={200}
onRowUpdated={this.handleRowUpdated} />
<button onClick={this.output} > Console data </button>
</div>
)
}
});
ReactDOM.render(<Example />, document.getElementById('container'));
I encounter some issues when I tried to reproduce. Anyway, after some changes I works fine:
- I removed the random date to avoid "Invalid Date"
- I fixed the formatter like this
formatter: ({value}) => <ExampleDate value={value} />
All works fine, but I always get the warning, because of the key props of your columns :(

Resources