I am trying to implement a feature where in on click of each row, I need to get the info of the row that is been clicked and corresponding row color should be changed to something else. And when I select multiple rows using Ctrl+mouse-click the corresponding rows color should also get changed, and need to get the info of corresponding rows in the form of array. I need to have a common getTrProps function that should implement both of this . Can someone help me out with this
Codesandbox: https://codesandbox.io/s/react-table-row-table-0bbyi
App
import * as React from "react";
import { render } from "react-dom";
import DataGrid from "./DataGrid";
import { Column } from "react-table";
interface IProps {}
interface IState {
data: IUser[];
columns: Column<IUser>[];
}
export interface IUser {
firstName: string;
status: "Submitted" | "Pending" | "Approved";
age: string;
}
export interface IColum {
Header: string;
accessor: string;
}
class App extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
data: [],
columns: []
};
}
componentDidMount() {
this.getData();
this.getColumns();
}
getData = () => {
const data: IUser[] = [
{ firstName: "Jack", status: "Submitted", age: "14" },
{ firstName: "Simon", status: "Pending", age: "15" },
{ firstName: "Pete", status: "Approved", age: "17" }
];
this.setState({ data });
};
getColumns = () => {
const columns: IColum[] = [
{
Header: "First Name",
accessor: "firstName"
},
{
Header: "Status",
accessor: "status"
},
{
Header: "Age",
accessor: "age"
}
];
this.setState({ columns });
};
onClickRow = (rowInfo: IUser) => {
console.log("You clicked: " + JSON.stringify(rowInfo));
};
render() {
return (
<>
<DataGrid
data={this.state.data}
columns={this.state.columns}
rowClicked={this.onClickRow}
/>
<DataGrid data={this.state.data} columns={this.state.columns} />
</>
);
}
}
DataGrid
import * as React from "react";
import ReactTable, {
RowInfo,
Column,
ComponentPropsGetterR
} from "react-table";
import "react-table/react-table.css";
import { IUser, IColum } from ".";
interface IProps {
data: IUser[];
columns: Column<IUser>[];
// The ? makes it optional
rowClicked?: (user: IUser) => void;
}
export default class DataGrid extends React.Component<IProps> {
rowClick: ComponentPropsGetterR = (state: any, rowInfo: RowInfo) => {
const rowClicked = this.props.rowClicked;
return rowClicked
? {
onClick: () => rowClicked(rowInfo.original as IUser)
}
: {};
};
render() {
return (
<ReactTable
data={this.props.data}
columns={this.props.columns}
getTrProps={this.rowClick}
/>
);
}
}
Here is Your Final Answer :
https://codesandbox.io/s/react-table-row-table-3xwxi
you can now hold Ctrl Key and Select as many row as you want and you can toggle between.
and if you don't hold the key you can select one
you can see each time you choose a row color of the row Changes.
and you have all the data in this.state.allData.
and all of this in typescript as you want from your sandbox.
Related
I made a example in following:
I am new to React and i am using React Select
import React, { Component, Fragment } from "react";
import Select from 'react-select';
const options = [
{ value: 'blues', label: 'Blues' },
{ value: 'rock', label: 'Rock' },
{ value: 'jazz', label: 'Jazz' },
{ value: 'orchestra', label: 'Orchestra' }
];
class DropDown3 extends Component {
constructor(props){
super(props)
this.state = {
selectOptions : [],
id: "",
name: ''
}
}
handleChange = (selectedOption) =>
{
console.log("selected",selectedOption)
this.setState({ selectedOption });
};
render()
{
const { selectedOption } = this.state;
return (
<Fragment>
<Select
options = {options}
onChange ={this.handleChange}
value = {selectedOption}
defaultValue={{ value: 'jazz', label: 'Jazz' }}
/>
<div>Hello you select {this.state.selectedOption}</div>
</Fragment>
);
}
}
export default DropDown3;
what i want is to display what i have selected in the dropdown so that i can pass it to another component.
The abouve code didnt run everytime i choose a menu
and it run only i comment out the
"Hello you select {this.state.selectedOption}"
thanks
You should initialize the selectedOption in the state, and when you update the state you should take the value of the selectedOption object.
import React, { Component, Fragment } from "react";
import Select from "react-select";
const options = [
{ value: "blues", label: "Blues" },
{ value: "rock", label: "Rock" },
{ value: "jazz", label: "Jazz" },
{ value: "orchestra", label: "Orchestra" }
];
class DropDown3 extends Component {
constructor(props) {
super(props);
this.state = {
selectOptions: [],
selectedOption: "",
id: "",
name: ""
};
}
handleChange = (selectedOption) => {
console.log("selected", selectedOption);
this.setState({ selectedOption: selectedOption.value });
};
render() {
const { selectedOption } = this.state;
return (
<Fragment>
<Select
options={options}
onChange={this.handleChange}
value={selectedOption}
defaultValue={{ value: "jazz", label: "Jazz" }}
/>
<div>Hello you select {this.state.selectedOption}</div>
</Fragment>
);
}
}
export default DropDown3;
I want to make a component for the rows in Ant Design Table, where each component will have their own state and based on that table rows will be shown. is it possible?
if possible how can I do it? an example will be helpful.
I tried the following example but it's showing 'No Data'
in item.js
import React, { Component } from "react";
import TableRow from "antd";
class Item extends Component {
constructor(props) {
super(props);
}
dataSource = [
{
key: "1",
details: "test",
price: 50
}
];
render() {
return <TableRow dataSource={this.dataSource} />;
}
}
export default Item;
and in itemlist.js
import React, { Component } from "react";
import { Table } from "antd";
import Item from "./item";
class ItemList extends Component {
constructor(props) {
super(props);
}
columns = [
{
title: "Item Details",
dataIndex: "details",
key: "details"
},
{
title: "Price",
dataIndex: "price",
key: "price"
}
];
render() {
return (
<Table column={this.columns}>
<Item key="1" />
</Table>
);
}
}
export default ItemList;
I'm still not totally get your requirements, but from I understand: you can define render in column definition, and there you'll get an row item:
class ItemList extends Component {
dataSource = [
{
key: "1",
details: "test",
price: 50
}
];
columns = [
{
title: "Item Details",
dataIndex: "details",
render: (text, record, index) => <Item {...record} />
key: "details"
}
];
render() {
return (
<Table columns={this.columns} dataSource={this.dataSource} />
);
}
}
If you just need to not show some rows based on data, you can filter dataSource accordingly.
I am trying to set a state using enzyme method. After setting a state inside test case I was able to get it back again within the test case which proves that setState is working and I can see the expected output in console. However, inside component I was not able to get state which was set by enzyme because of this my is failing and I am not getting desire view back from component, here is screenshot. You can see there is not data grid table rendered despite having rows data.
table.js
import React, { Component } from 'react';
import styled from 'styled-component';
import ReactDataGrid from 'react-data-grid';
import { Filters } from 'react-data-grid-addons';
import PropTypes from 'prop-types';
export class Table extends Component {
constructor(props) {
super(props);
const {
NumericFilter,
AutoCompleteFilter,
} = Filters;
this.columns = [
{ key: "id", name: "ID", editable: true },
{ key: "title", name: "Title", editable: true },
{ key: "complete", name: "Complete", editable: true }
];
this.state = {
rows: [],
};
}
renderRow = (i) => {
const { rows } = this.state;
return rows[i];
}
render() {
const { className } = this.props;
const { rows } = this.state;
console.log('rows Length', rows.length) // always 0
return (
<div className={className}>
{rows.length
? (
<ReactDataGrid
rowHeight={50}
columns={this.columns}
rowGetter={this.renderRow}
rowsCount={rows.length}
/>
)
: <span id="no-product-message">No Items to be Shown</span>
}
</div>
);
}
}
Table.propTypes = {
className: PropTypes.string,
};
Table.defaultProps = {
className: '',
};
export default styled(Table)`
.react-grid-HeaderCell{
white-space: normal !important;
}
.react-grid-Cell__value{
display: flex;
align-items: center;
}
`;
mountWithTheme
export const mountWithTheme = (children, options) => (
mount(<ThemeProvider theme={theme}>{children}</ThemeProvider>, options)
);
test case
it('should render table if product data is available', () => {
const wrapper = mountWithTheme(<Table />).find(Table);
const instance = wrapper.instance();
jest.spyOn(instance, 'renderRow');
instance.setState({
rows: [{ id: 0, title: "Task 1", complete: 20 }],
});
console.log(instance.state.rows) // [{ id: 0, title: "Task 1", complete: 20 }]
expect(wrapper.find('ReactDataGrid').exists()).toBe(true);
expect(instance.renderRow).toHaveBeenCalledTimes(1);
});
Using a sidebar component from [office-ui-fabric-react][1].
I want to sidebar to start in the Collapsed state, but I am having difficulty setting the state of the ISidebar interface to do this.
How can I toggleCollapsed on this imported component?
export interface ISidebar {
/**
* Toggles the sidebar state to put the sidebar in or out of collapsed mode
* #type {(boolean) => void}
*/
toggleCollapsed: () => void;
}
export class SidebarExample extends React.Component {
public render(): JSX.Element {
this.state = {
active: true
};
return (
<Sidebar
id={'sidebar-collapsed'}
collapsible={true}
theme={getTheme()}
/>
)
Public methods (e.g. toggleCollapsed) of Sidebar component are accessible through componentRef, for example:
<Sidebar componentRef={initSidebar} />
const initSidebar = (sideBar: ISidebar) => {
sideBar.toggleCollapsed();
};
Example
The initial collapsed state could be set like this:
const initSidebar = (ref: ISidebar) => {
ref.setCollapsed(true);
};
const SidebarBasicExample: React.SFC<{}> = props => {
return (
<Sidebar
componentRef={initSidebar}
collapsible={true}
id={"1"}
theme={getTheme()}
items={[
{
key: "basic-example-item1",
name: "Item 1",
iconProps: { iconName: "BuildQueue" },
active: false
},
{
key: "basic-example-item2",
name: "Item 2",
iconProps: { iconName: "Bullseye" },
active: true
}
]}
/>
);
};
With Vadim's help, my answer.
import { getTheme } from 'office-ui-fabric-react';
import * as React from 'react';
import { Sidebar, ISidebar } from '#uifabric/experiments/lib/Sidebar';
const initSidebar = (sideBar: ISidebar) => {
sideBar.toggleCollapsed();
};
export class SidebarCollapsibleExample extends React.Component {
public render(): JSX.Element {
this.state = {
active: true
};
return (
<Sidebar
id={'sidebar-collapsed'}
collapsible={true}
theme={getTheme()}
collapseButtonAriaLabel={'sitemap'}
componentRef={initSidebar}
items={[
{
key: 'collapsible-example-item1',
name: 'Item 1',
iconProps: { iconName: 'BuildQueue' },
active: false
} ]}
/>
);
}
}
I'm trying to follow the example here from the office-ui-fabric-react repo simply to test the new focusedIndex function to scroll a selection into view.
However, WebStorm is highlighting a TS2322 error in the render() function trying to set the componentRef property to a class variable:
(short error)
TS2322: Type '{componentRef: RefObject... is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes...
The error occurs when using the full unmodified code from the link, but here's a snippet of the relevant class code for reference and the ** affected line ** in the render() function:
import * as React from 'react';
import { BaseComponent } from 'office-ui-fabric-react/lib/Utilities';
import { DefaultButton } from 'office-ui-fabric-react/lib/Button';
import { Fabric } from 'office-ui-fabric-react/lib/Fabric';
import { IDetailsList, DetailsList, IColumn } from 'office-ui-fabric-react/lib/DetailsList';
import { Checkbox } from 'office-ui-fabric-react/lib/Checkbox';
import './DetailsList.Grouped.Example.scss';
export class DetailsListGroupedExample extends BaseComponent<
{},
{
items: {}[];
showItemIndexInView: boolean;
}
>
{
private _root = React.createRef<IDetailsList>();
constructor(props: {}) {
super(props);
this.state = {
items: _items,
showItemIndexInView: false
};
}
public render() {
const { items } = this.state;
return (
<Fabric className="DetailsList-grouped-example">
<div>
<Checkbox
label="Show index of the first item in view when unmounting"
checked={this.state.showItemIndexInView}
onChange={this._onShowItemIndexInViewChanged}
/>
</div>
<DefaultButton onClick={this._addItem} text="Add an item" />
<DetailsList
componentRef={this._root} //**TS2322 ERROR HERE**
items={items}
groups={[
{
key: 'groupred0',
name: 'By "red"',
startIndex: 0,
count: 2
},
{
key: 'groupgreen2',
name: 'By "green"',
startIndex: 2,
count: 0
},
{
key: 'groupblue2',
name: 'By "blue"',
startIndex: 2,
count: items.length - 2
}
]}
columns={_columns}
ariaLabelForSelectAllCheckbox="Toggle selection for all items"
ariaLabelForSelectionColumn="Toggle selection"
groupProps={{
showEmptyGroups: true
}}
onRenderItemColumn={this._onRenderColumn}
/>
</Fabric>
);
}
}
What am I doing wrong or what do I need to do to resolve this compile error?
So, on the example i've get rid of
private _root = React.createRef<IDetailsList>
and all of references to this object. Then example works like a charm.
It looks like something has been changed in fabric react controls, but codesamples on their website has not been updated which is annoying.
My code:
import * as React from 'react';
import styles from './RsfDictionaries.module.scss';
import { IRsfDictionariesProps } from './IRsfDictionariesProps';
import { escape } from '#microsoft/sp-lodash-subset';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
import { Toggle } from 'office-ui-fabric-react/lib/Toggle';
import { DetailsList, DetailsListLayoutMode, Selection, SelectionMode, IColumn, IDetailsList } from 'office-ui-fabric-react/lib/DetailsList';
import { MarqueeSelection } from 'office-ui-fabric-react/lib/MarqueeSelection';
import { IDocument, IDetailsListDocumentsExampleState } from './states';
import { BaseComponent } from 'office-ui-fabric-react/lib/Utilities';
import { DefaultButton } from 'office-ui-fabric-react/lib/Button';
import { Fabric } from 'office-ui-fabric-react/lib/Fabric';
import { Checkbox } from 'office-ui-fabric-react/lib/Checkbox';
const _columns = [
{
key: 'name',
name: 'Name',
fieldName: 'name',
minWidth: 100,
maxWidth: 200,
isResizable: true
},
{
key: 'color',
name: 'Color',
fieldName: 'color',
minWidth: 100,
maxWidth: 200
}
];
const _items = [
{
key: 'a',
name: 'a',
color: 'red'
},
{
key: 'b',
name: 'b',
color: 'red'
},
{
key: 'c',
name: 'c',
color: 'blue'
},
{
key: 'd',
name: 'd',
color: 'blue'
},
{
key: 'e',
name: 'e',
color: 'blue'
}
];
export default class RsfDictionaries extends React.Component<IRsfDictionariesProps, {
items: {}[];
showItemIndexInView: boolean;
}> {
constructor(props: any) {
super(props);
this.state = {
items: _items,
showItemIndexInView: false
};
}
public componentWillUnmount() {
if (this.state.showItemIndexInView) {
const itemIndexInView = 0;//this._root!.current!.getStartItemIndexInView();
alert('unmounting, getting first item index that was in view: ' + itemIndexInView);
}
}
private _root :IDetailsList; //React.createRef<IDetailsList>();
public render(): React.ReactElement<IRsfDictionariesProps> {
const { items } = this.state;
return (
<Fabric className="DetailsList-grouped-example">
<div>
<Checkbox
label="Show index of the first item in view when unmounting"
checked={this.state.showItemIndexInView}
onChange={this._onShowItemIndexInViewChanged}
/>
</div>
<DefaultButton onClick={this._addItem} text="Add an item" />
<DetailsList
//={this._root}
items={items}
groups={[
{
key: 'groupred0',
name: 'By "red"',
startIndex: 0,
count: 2
},
{
key: 'groupgreen2',
name: 'By "green"',
startIndex: 2,
count: 0
},
{
key: 'groupblue2',
name: 'By "blue"',
startIndex: 2,
count: items.length - 2
}
]}
columns={_columns}
ariaLabelForSelectAllCheckbox="Toggle selection for all items"
ariaLabelForSelectionColumn="Toggle selection"
groupProps={{
showEmptyGroups: true
}}
onRenderItemColumn={this._onRenderColumn}
/>
</Fabric>
);
}
private _addItem = (): void => {
const items = this.state.items;
this.setState(
{
items: items.concat([
{
key: 'item-' + items.length,
name: 'New item ' + items.length,
color: 'blue'
}
])
},
() => {
//if (this._root.current) {
//this._root.current.focusIndex(items.length, true);
//}
}
);
};
private _onRenderColumn(item: any, index: number, column: IColumn) {
let value = item && column && column.fieldName ? item[column.fieldName] : '';
if (value === null || value === undefined) {
value = '';
}
return (
<div className={'grouped-example-column'} data-is-focusable={true}>
{value}
</div>
);
}
private _onShowItemIndexInViewChanged = (event: React.FormEvent<HTMLInputElement>, checked: boolean): void => {
this.setState({
showItemIndexInView: checked
});
};
}