TS2322 error with Office UI Fabric DetailsList component - reactjs

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
});
};
}

Related

Fabric UI DetailsList control - Dynamically load group items

I'm using grouped DetailsList Fabric UI component in custom SPFx webpart for displaying list data.
I need to load items of the group dynamically from the server by the API call after group expand, but can't find any available group expand callbacks in DetailsList component with available exposed group props (name of the group, etc.) as a method parameter for building a request string. It should look like that:
https://contoso.sharepoint.com/site/_api/web/Lists/getbytitle('ListTitle')/RenderListDataAsStream?#listUrl=&View=&IsGroupRender=TRUE&DrillDown=1&GroupString=%3B%23Exel%20Format%20Files%3B%23%3B%23&
Basically, I want to achieve behavior of the standard modern Document Library webpart existing in Sharepoint 2019. Just need a callback on group expand for update items array. Any other ways to achieve this with DetailsList component?
Code sample of the component (from documentation):
import * as React from 'react';
import {
BaseComponent,
DefaultButton,
DetailsHeader,
DetailsList,
IColumn,
IDetailsHeaderProps,
IDetailsList,
IGroup,
IRenderFunction,
IToggleStyles,
mergeStyles,
Toggle
} from 'office-ui-fabric-react';
const margin = '0 20px 20px 0';
const controlWrapperClass = mergeStyles({
display: 'flex',
flexWrap: 'wrap'
});
const toggleStyles: Partial<IToggleStyles> = {
root: { margin: margin },
label: { marginLeft: 10 }
};
export interface IDetailsListGroupedExampleItem {
key: string;
name: string;
color: string;
}
export interface IDetailsListGroupedExampleState {
items: IDetailsListGroupedExampleItem[];
groups: IGroup[];
showItemIndexInView: boolean;
isCompactMode: boolean;
}
const _blueGroupIndex = 2;
export class DetailsListGroupedExample extends BaseComponent<{}, IDetailsListGroupedExampleState> {
private _root = React.createRef<IDetailsList>();
private _columns: IColumn[];
constructor(props: {}) {
super(props);
this.state = {
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' }
],
// This is based on the definition of items
groups: [
{ key: 'groupred0', name: 'Color: "red"', startIndex: 0, count: 2 },
{ key: 'groupgreen2', name: 'Color: "green"', startIndex: 2, count: 0 },
{ key: 'groupblue2', name: 'Color: "blue"', startIndex: 2, count: 3 }
],
showItemIndexInView: false,
isCompactMode: false
};
this._columns = [
{ key: 'name', name: 'Name', fieldName: 'name', minWidth: 100, maxWidth: 200, isResizable: true },
{ key: 'color', name: 'Color', fieldName: 'color', minWidth: 100, maxWidth: 200 }
];
}
public componentWillUnmount() {
if (this.state.showItemIndexInView) {
const itemIndexInView = this._root.current!.getStartItemIndexInView();
alert('first item index that was in view: ' + itemIndexInView);
}
}
public render() {
const { items, groups, isCompactMode } = this.state;
return (
<div>
<div className={controlWrapperClass}>
<DefaultButton onClick={this._addItem} text="Add an item" styles={{ root: { margin: margin } }} />
<Toggle label="Compact mode" inlineLabel checked={isCompactMode} onChange={this._onChangeCompactMode} styles={toggleStyles} />
<Toggle
label="Show index of first item in view when unmounting"
inlineLabel
checked={this.state.showItemIndexInView}
onChange={this._onShowItemIndexInViewChanged}
styles={toggleStyles}
/>
</div>
<DetailsList
componentRef={this._root}
items={items}
groups={groups}
columns={this._columns}
ariaLabelForSelectAllCheckbox="Toggle selection for all items"
ariaLabelForSelectionColumn="Toggle selection"
onRenderDetailsHeader={this._onRenderDetailsHeader}
groupProps={{
showEmptyGroups: true
}}
onRenderItemColumn={this._onRenderColumn}
compact={isCompactMode}
/>
</div>
);
}
private _addItem = (): void => {
const items = this.state.items;
const groups = [...this.state.groups];
groups[_blueGroupIndex].count++;
this.setState(
{
items: items.concat([
{
key: 'item-' + items.length,
name: 'New item ' + items.length,
color: 'blue'
}
]),
groups
},
() => {
if (this._root.current) {
this._root.current.focusIndex(items.length, true);
}
}
);
};
private _onRenderDetailsHeader(props: IDetailsHeaderProps, _defaultRender?: IRenderFunction<IDetailsHeaderProps>) {
return <DetailsHeader {...props} ariaLabelForToggleAllGroupsButton={'Expand collapse groups'} />;
}
private _onRenderColumn(item: IDetailsListGroupedExampleItem, index: number, column: IColumn) {
const value = item && column && column.fieldName ? item[column.fieldName as keyof IDetailsListGroupedExampleItem] || '' : '';
return <div data-is-focusable={true}>{value}</div>;
}
private _onShowItemIndexInViewChanged = (event: React.MouseEvent<HTMLInputElement>, checked: boolean): void => {
this.setState({ showItemIndexInView: checked });
};
private _onChangeCompactMode = (ev: React.MouseEvent<HTMLElement>, checked: boolean): void => {
this.setState({ isCompactMode: checked });
};
}
I was looking for this today also and after checking the source code I figured it out. Use the groupProps.headerPropsto set a callback on group collapsing/expanding
<DetailsList
...
groupProps={{
headerProps: {
onToggleCollapse: this._onGroupToggleCollapse
}
}}
/>
So, the basic logic for this action is (using onToggleCollapse callback):
private _onToggleCollapse(props: IGroupDividerProps): () => void {
...
if (props.group.data.isLoaded === false && props.group.isCollapsed === false && props.group.level > 0) {
...
let data: any = this._getGroupItems(props.group, isLoadAll, {}).then((resp: any) => {
resp.json().then((responseJSON: any) => {
...
updatedItems = this.state.items.map((el: any, i: number) => {
...
});
...
this.setState({
items: [...updatedItems],
groups: [...this.state.groups]
});
});
});
...
}
...
return () => {
props.onToggleCollapse!(props!.group!);
};
}
We need to check for expanding to prevent updates on collapsing of the group.

ToggleCollapsed on imported sidebar reactjs component

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
} ]}
/>
);
}
}

Disable selection for rows with particular Row Ids in devexpress react Grid?

I am working on devexpress react grid and I am new to react. I need to disable the selection of rows based on the condition. I struggle here to disable the selection of particular rows rather than all the rows. Please help me.
https://stackblitz.com/edit/react-deg9yu?file=index.js
The above link has the demo to disable the selection if the 3 rows are selected. But in my scenario the selection checkbox should be enabled for only the rowid [0,1,5]. Other rows should be disabled for selection by default.
I found the answer to my question on below link.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
Getter,
Plugin
} from '#devexpress/dx-react-core';
import {
SelectionState,
IntegratedSelection
} from '#devexpress/dx-react-grid';
import {
Grid,
Table,
TableHeaderRow,
TableSelection
} from '#devexpress/dx-react-grid-bootstrap3';
const filters = [0,2,5];
const columns = [
{ name: 'id', title: 'ID' },
{ name: 'product', title: 'Product' },
{ name: 'owner', title: 'Owner' },
];
const rows = [
{ id: 0, product: 'DevExtreme', owner: 'DevExpress' },
{ id: 1, product: 'DevExtreme Reactive', owner: 'DevExpress' },
{ id: 2, product: 'DevExtreme Reactive 1', owner: 'DevExpress' },
{ id: 3, product: 'DevExtreme Reactive 2', owner: 'DevExpress' },
{ id: 4, product: 'DevExtreme', owner: 'DevExpress' },
{ id: 5, product: 'DevExtreme Reactive', owner: 'DevExpress' },
{ id: 6, product: 'DevExtreme Reactive 1', owner: 'DevExpress' },
{ id: 7, product: 'DevExtreme Reactive 2', owner: 'DevExpress' },
];
const rowSelectionEnabled = row => row.product === 'DevExtreme' ;
class PatchedIntegratedSelection extends React.PureComponent {
render() {
const { rowSelectionEnabled, ...restProps } = this.props;
return (
<Plugin>
<Getter
name="rows"
computed={({ rows }) => {
this.rows = rows;
return rows.filter(rowSelectionEnabled);
}}
/>
<IntegratedSelection {...restProps} />
<Getter
name="rows"
computed={() => this.rows}
/>
</Plugin>
)
}
};
class PatchedTableSelection extends React.PureComponent {
render() {
const { rowSelectionEnabled, ...restProps } = this.props;
return (
<TableSelection
cellComponent={(props) => this.props.rowSelectionEnabled(props.tableRow.row) ? (
<TableSelection.Cell {...props} />
) : (
<Table.StubCell {...props} />
)}
{...restProps}
/>
);
}
}
export default class App extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
selection: []
};
this.changeSelection = selection => this.setState({ selection });
}
render() {
const { selection } = this.state;
return (
<div>
<span>Selection: {JSON.stringify(selection)}</span>
<Grid
rows={rows}
columns={columns}
>
<SelectionState
selection={selection}
onSelectionChange={this.changeSelection}
/>
<PatchedIntegratedSelection
rowSelectionEnabled={rowSelectionEnabled}
/>
<Table />
<TableHeaderRow />
<PatchedTableSelection
showSelectAll
rowSelectionEnabled={rowSelectionEnabled}
/>
</Grid>
</div>
);
}
}
ReactDOM.render(
<App/>,
document.getElementById('root')
);
Links: https://github.com/DevExpress/devextreme-reactive/issues/1706
For anyone who is interested I achieved this by doing the following.
render() {
const {...restProps} = this.props;
return (
...
<TableSelection cellComponent={this._selectableRow}
{...restProps}
/>
...
);
}
...
_selectableRow(props)
{
const {...restProps} = props;
return props.row.type === "folder" ? <Table.StubCell/> : <TableSelection.Cell {...restProps}/>
}

How to remove item from a generic Array in React Typescript?

Can someone show me how to remove an object in the newly created array? parameter "index" does not work well in this case as it is not really the index of the newly created array.
I am creating the new array in the onchange event.
Here I am including the full code. Just in case someone has got an idea.
import * as React from 'react';
import styles from './ListItems.module.scss';
import { IListItemsProps } from './IListItemsProps';
import { escape } from '#microsoft/sp-lodash-subset';
import {DropdownBasicExample} from './DropdownExample'
import { IDropdownOption, DropdownMenuItemType } from 'office-ui-fabric-react';
import { DropdownBasicExample2 } from './Dropdown2.Basic.Example';
export interface IListItemsState{
selectedItems:IDropdownOption[];
selectedSite:IDropdownOption;
}
export default class ListItems extends React.Component<IListItemsProps, IListItemsState> {
private myWeb:IDropdownOption;
constructor(props){
super(props);
this.state = {
selectedItems:[],
selectedSite:null
}
}
private sites = [
{ key: 'Header', text: 'Actions', itemType: DropdownMenuItemType.Header },
{ key: 'A', text: 'Site a', title: 'I am Site a.' },
{ key: 'B', text: 'Site b' },
{ key: 'C', text: 'Site c' },
{ key: 'D', text: 'Site d' },
{ key: 'E', text: 'Site e' },
{ key: 'F', text: 'Site f' },
{ key: 'G', text: 'Site g' },
{ key: 'H', text: 'Site h' },
{ key: 'I', text: 'Site i' },
{ key: 'J', text: 'Site j' }
];
private loadSites= (): Promise<IDropdownOption[]> => {
return new Promise<IDropdownOption[]>((resolve: (sites: IDropdownOption[]) => void, reject: (error: any) => void) => {
setTimeout(() => {
resolve(this.sites);
}, 1000);
});
}
private onChanged = (item: IDropdownOption, index?: number): void => {
let mySelectedItems = [...this.state.selectedItems];
if (item.selected) {
mySelectedItems.push(item);
} else {
mySelectedItems = mySelectedItems.filter(selectedItem => selectedItem !== item);
}
this.setState({
selectedItems: mySelectedItems
});
console.log(mySelectedItems);
}
public render(): React.ReactElement<IListItemsProps> {
const {selectedSite} = this.state;
return (
<div className={styles.listItems}>
<DropdownBasicExample loadOptions={this.loadSites} onChanged={this.onChanged} />
<div id="showItems"></div>
<ul>{
this.state.selectedItems.map((site:IDropdownOption)=> {
return <li>{site.text}</li>
})
}
</ul>
<div>selected Site {
selectedSite ? selectedSite.key: "is empty"
}</div>
</div>
);
}
}
DropdownBasicExample2
import * as React from 'react';
import { PrimaryButton } from 'office-ui-fabric-react/lib/Button';
import { Dropdown, IDropdown, DropdownMenuItemType, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
import './Dropdown.Basic.Example.scss';
import { BaseComponent, createRef, IBaseProps } from 'office-ui-fabric-react';
export interface IDropdownBasicExample2State{
selectedItem?: IDropdownOption;
selectedItems: IDropdownOption[];
options: IDropdownOption[];
}
export interface IDropdownBasicExample2Props extends IBaseProps{
onChanged?: (option: IDropdownOption, index?: number) => void;
Options: IDropdownOption[];
}
export class DropdownBasicExample2 extends BaseComponent<IDropdownBasicExample2Props,IDropdownBasicExample2State> {
private _basicDropdown = createRef<IDropdown>();
private alphas:IDropdownOption[];
private array2: Array<IDropdownOption>;
constructor(props: IDropdownBasicExample2Props) {
super(props);
this.state = {
selectedItem: null,
selectedItems: [],
options:[]
};
}
componentDidMount(){
}
public render() {
const { selectedItem, selectedItems } = this.state;
return (
<div className="docs-DropdownExample">
<Dropdown
placeHolder="Select options"
label="Multi-Select controlled example:"
selectedKey={selectedItem ? selectedItem.key : undefined}
key={selectedItem ? selectedItem.key : undefined}
onChanged={this.onChangeMultiSelect}
multiSelect
options={this.props.Options}
/>
</div>
);
}
public onChangeMultiSelect = (item: IDropdownOption,index:number): void => {
this.props.onChanged(item,index);
};
}
You could filter out the item from the array.
private onChanged = (item: IDropdownOption, index?: number): void => {
let mySelectedItems = [...this.state.selectedItems];
if (item.selected) {
mySelectedItems.push(item);
} else {
mySelectedItems = mySelectedItems.filter(
selectedItem => selectedItem !== item
);
}
this.setState({
selectedItems: mySelectedItems
});
};
Give this a try. Remove items based on a property. In this case I am using the key.
private onChanged = (item: IDropdownOption, index?: number): void => {
let mySelectedItems = [...this.state.selectedItems];
if (item.selected) {
mySelectedItems.push(item);
} else {
mySelectedItems = mySelectedItems.filter(selectedItem => selectedItem.key !== item.key);
}
this.setState({
selectedItems: mySelectedItems
});
}

React Material UI makeSelectable List Not Compatible With Nested ListItem Component

I have a problem that my makeSelectable code is not working when I used the ListItem from child component instead of using ListItem directly. Here is my example code (the workingLinkItems can be selected normally but the notWorkingLinkItems is not selectable).
import React, { Component, PropTypes } from 'react'
import { List, makeSelectable, ListItem } from 'material-ui/List'
import { wrapState } from 'helpers/utils'
const { func, shape, string, number } = PropTypes
class TryListItem extends Component {
static propTypes = {
onOpenLink: func.isRequired,
linkItem: shape({
key: number.isRequired,
link: string.isRequired,
text: string.isRequired,
}).isRequired,
}
handleOpenLink = () => {
this.props.onOpenLink(this.props.linkItem.link)
}
render () {
const { key, link, text } = this.props.linkItem
return <ListItem
value={key}
primaryText={text}
onTouchTap={this.handleOpenLink} />
}
}
let SelectableList = makeSelectable(List)
SelectableList = wrapState(SelectableList)
class TrySelectableList extends Component {
handleOpenLink = (location) => {
console.log('The page will be redirected to: ', location)
}
render () {
const links = [
{
key: 1,
link: '/home',
text: 'Home',
},
{
key: 2,
link: '/about',
text: 'About Us',
},
{
key: 3,
link: '/contact',
text: 'Contact Us',
},
]
const notWorkingLinkItems = links.map((link) => (
<TryListItem
onOpenLink={this.handleOpenLink}
linkItem={link} />
))
const workingLinkItems = links.map((link) => (
<ListItem
value={link.key + 3}
primaryText={link.text}
onTouchTap={this.handleOpenLink} />
))
return (
<div>
<SelectableList defaultValue={1}>
{notWorkingLinkItems}
{workingLinkItems}
</SelectableList>
</div>
)
}
}
export default TrySelectableList
Any idea what's wrong with my code?
Finally after a lot of trial tinkering with material-ui makeSelectable function. I ended up creating my own selectable style.
Here is my code solution for my problem:
import React, { Component, PropTypes } from 'react'
import { List, ListItem } from 'material-ui/List'
const { bool, func, shape, string, number } = PropTypes
class TryListItem extends Component {
static propTypes = {
selected: bool.isRequired,
onOpenLink: func.isRequired,
linkItem: shape({
link: string.isRequired,
text: string.isRequired,
}).isRequired,
}
handleOpenLink = () => {
this.props.onOpenLink(this.props.linkItem.link, this.props.linkItem.key)
}
render () {
const { key, link, text } = this.props.linkItem
const styles = this.props.selected
? { backgroundColor: 'rgba(0, 0, 0, 0.2)', }
: {}
return <ListItem
primaryText={text}
onTouchTap={this.handleOpenLink}
style={styles} />
}
}
class TrySelectableList extends Component {
componentWillMount = () => {
this.buildLink()
}
buildLink = (selectedIndex = 0) => {
const initialLinks = [
{
key: 1,
link: '/home',
text: 'Home',
selected: false,
},
{
key: 2,
link: '/about',
text: 'About Us',
selected: false,
},
{
key: 3,
link: '/contact',
text: 'Contact Us',
selected: false,
},
]
const links = initialLinks.map((link) => {
if (link.key === selectedIndex) {
link.selected = true
}
return link
})
this.setState({
links: links
})
}
handleOpenLink = (location, index) => {
console.log('The page will be redirected to: ', location)
this.buildLink(index)
}
render () {
const workingLinkItems = this.state.links.map((link) => (
<TryListItem
key={link.key}
selected={link.selected}
onOpenLink={this.handleOpenLink}
linkItem={link} />
))
return (
<div>
<List>
{workingLinkItems}
</List>
</div>
)
}
}
export default TrySelectableList

Resources