I am needing to add bit of text in the sidebar of the following code. In each section, I need to have a count of the number of checkboxes selected. Is it at all possible to do this in a functional component as I have? Any examples that I have found so far are only for class components. I would like to keep it as a functional component if possible.
I have the code below, but here is a working version too:
https://codesandbox.io/s/react-playground-forked-jgmof?file=/index.js
import React, { useState } from "react";
import ReactDOM from "react-dom";
import styled from "styled-components";
import { categoryData } from "./data";
const Menu = (props) => {
const [showPanel, togglePanel] = useState(false);
return (
<MenuWrapper>
<p>Showing 20 results</p>
<div className="button-wrapper">
<p>Filter By</p>
{categoryData.map((categorybutton, i) => (
<div key={i}>
<button key={i} onClick={() => togglePanel(!showPanel)}>
{categorybutton.category}
</button>
</div>
))}
<div>
{showPanel && (
<Sidebar>
{categoryData.map((categorysection, i) => (
<details className="dropdown-header">
<summary>{categorysection.category}</summary>
{categorysection.data.map((categorylabel, i) => (
<div key={i}>
<input
type="checkbox"
id="vehicle1"
name="vehicle1"
value="Bike"
/>
<label for="vehicle1">{categorylabel.label}</label>
</div>
))}
</details>
))}
</Sidebar>
)}
</div>
<p>Toggle</p>
<p>Clear all filters</p>
</div>
</MenuWrapper>
);
};
const MenuWrapper = styled.div`
width: 90vw;
display: flex;
justify-content: space-between;
.button-wrapper {
display: flex;
}
`;
const Sidebar = styled.div`
position: fixed;
width: 200px;
height: 100vh;
background: white;
top: 0;
left: 0;
z-index: 100000;
text-align: left;
.dropdown-header {
background: #f7f7f7;
margin: 20px;
}
`;
ReactDOM.render(<Menu />, document.getElementById("container"));
export const categoryData = [
{
category: "user",
data: [
{ checked: false, value: "Me", label: "Me" },
{ checked: false, value: "Kids", label: "Kids" },
{ checked: false, value: "Guestroom", label: "Guestroom" }
]
},
{
category: "comfort",
data: [
{ checked: false, value: "Ultra-Soft", label: "Ultra-Soft" },
{ checked: false, value: "Soft", label: "Soft" },
{ checked: false, value: "Medium", label: "Medium" },
{ checked: false, value: "Medium-Firm", label: "Medium-Firm" },
{ checked: false, value: "Firm", label: "Firm" },
{ checked: false, value: "Ultra-Firm", label: "Ultra-Firm" },
{ checked: false, value: "Unsure", label: "Unsure" }
]
},
{
category: "type",
data: [
{ checked: false, value: "Pillow Top", label: "Pillow Top" },
{ checked: false, value: "Open Coil", label: "Open Coil" },
{ checked: false, value: "Pocketed Coil", label: "Pocketed Coil" },
{ checked: false, value: "Quantum Coil", label: "Quantum Coil" },
{ checked: false, value: "Memory Foam", label: "Memory Foam" },
{ checked: false, value: "Latex", label: "Latex" },
{ checked: false, value: "Unsure", label: "Unsure" }
]
},
{
category: "budget",
data: [
{ checked: false, value: 500, label: "Under $500" },
{ checked: false, value: 1000, label: "$501 - $1000" },
{ checked: false, value: 1600, label: "1001 - $1600" },
{ checked: false, value: 2500, label: "$1601 - $2500" },
{ checked: false, value: 2501, label: "$2500 and up" },
{ checked: false, value: "Unsure", label: "Unsure" }
]
}
];
If I understand correctly, you wan't to show the total number of selected items on each category.
It would be easy if we'll create a new component for the section that will have it's own state tracking its selected items.
Let's call it CategorySection. It would then have a selected state that will be an array (empty by default) of its selected items. To update our selected state, we have to fireup a function everytime any of the checkbox is changed — if the checkbox is checked, we add the current item to our selected state otherwise it will be removed.
Then to display the total selected items, we can simply count the length of our selected state.
function CategorySection({ categorysection }) {
const [selected, setSelected] = useState([]);
function onChange(event, item) {
if (event.target.checked) {
setSelected([...selected, item]);
} else {
setSelected((prev) =>
prev.filter((currItem) => currItem.value !== item.value)
);
}
}
return (
<details className="dropdown-header">
<summary>
{categorysection.category}{" "}
{selected.length > 0 ? selected.length : null}
</summary>
{categorysection.data.map((categorylabel, i) => (
<div key={i}>
<input
type="checkbox"
id={categorylabel.value}
name="vehicle1"
value="Bike"
onChange={(event) => onChange(event, categorylabel)}
/>
<label for={categorylabel.value}>{categorylabel.label}</label>
</div>
))}
</details>
);
}
PS: You should have a unique id for every checkbox on your page.
Related
I have an application where the user will select a seat and then will click reserve and the seats will be greyed out. For some reason my object array of seats are not updating in the array and the seats are not greying out. when I log the seating sometimes, the isReserved is true, and when I log it again it goes back to false.
Here is what the code looks like:
const seats: any[] = [
{ id: 1, isSelected: false, isReserved: false },
{ id: 2, isSelected: false, isReserved: false },
{ id: 3, isSelected: false, isReserved: false },
{ id: 4, isSelected: false, isReserved: true },
{ id: 5, isSelected: false, isReserved: false },
{ id: 6, isSelected: false, isReserved: false },
];
const Seatbooking = () => {
const [isSelected, setIsSelected] = useState(0);
const [seating, setSeating] = useState(seats);
function onSelected(select: any) {
console.log(select.id);
console.log("selected ", select);
setIsSelected(select.id);
console.log("it is selected ", select.id);
}
const onReserved = (id: any) => {
setSeating((seat) => {
return seat.map((item) => {
return item.id === id
? { ...item, isReserved: !item.isReserved }
: item;
});
});
};
return (
<>
<div className="grid-container">
{seats.map((seat) => (
<div style={{ width: "50%" }}>
<button
key={seat.id}
style={{
backgroundColor:
seat.isReserved === true
? "grey"
: seat.id === isSelected
? "red"
: "#2d95c9",
}}
className="seat_buttons"
onClick={() => onSelected(seat)}
>
{seat.id}
</button>
</div>
))}
</div>
<button className="seat_booking" onClick={() => onReserved(isSelected)}>
Reserve seat
</button>
</>
);
};
Working solution with fixed naming and optimised conditions.
import { useState } from 'react';
const seats = [
{ id: 1, isSelected: false, isReserved: false },
{ id: 2, isSelected: false, isReserved: false },
{ id: 3, isSelected: false, isReserved: false },
{ id: 4, isSelected: false, isReserved: true },
{ id: 5, isSelected: false, isReserved: false },
{ id: 6, isSelected: false, isReserved: false },
];
export const Seatbooking = () => {
const [selectedSeatId, setSelectedSeatId] = useState(0);
const [seating, setSeating] = useState(seats);
function onSelected(select) {
console.log(select.id);
console.log('selected ', select);
setSelectedSeatId(select.id);
console.log('it is selected ', select.id);
}
const onReserved = (id) => {
const updatedArr = seating.map((item) => {
return item.id === id ? { ...item, isReserved: !item.isReserved } : item;
});
setSeating(updatedArr);
};
return (
<>
<div className="grid-container">
{seating.map((seat) => (
<div key={seat.id} style={{ width: '50%', display: 'flex' }}>
<button
style={{
backgroundColor: seat.isReserved
? 'grey'
: seat.id === selectedSeatId
? 'red'
: '#2d95c9',
}}
className="seat_buttons"
onClick={() => onSelected(seat)}
>
{seat.id}
</button>
</div>
))}
</div>
<button className="seat_booking" onClick={() => onReserved(selectedSeatId)}>
Reserve seat
</button>
</>
);
};
You should work with state in your component, not with constant.
You do not need callback in your setSeating.
isSelected - name for boolean value. You store id - call it selectedSeatId.
Key should be on div, not on button.
seats.map((seat) => (
You're mapping over the original array, not your state variable. Change it to:
seating.map((seat) => (
As shown in the picture, I have created a similar collapsible table, but I am unable to display the number of items in the collapsible rows. I am referring to the headings written in blue colour (in the picture)
Can someone help me to understand, how I can display the name of first items followed by the number of remaining items in heading of each main row ( for eg ( basketball..+2). Also I am using api call to fetch data in the table
enter code here
export const columns = [
{
Header: () => (
<div />
),
accessor: 'name',
maxWidth: 300,
Cell: row => (
<div className='first-column'>{row.value}</div>
)
}
];
export const subComponent = row => {
return (
<div>
{row.original.types.map((type, id) => {
return (
<div className='subRow' key={ id }>{ type.name }</div>
);
})}
</div>
);
};
export const data = [
{
id: '12345',
name: 'sports',
types: [
{
name: 'basketball',
id: '1'
},
{
name: 'soccer',
id: '2'
},
{
name: 'baseball',
id: '3'
}
]
},
{
id: '678910',
name: 'food',
types: [
{
name: 'pizza',
id: '4'
},
{
name: 'hamburger',
id: '5'
},
{
name: 'salad',
id: '6'
}
]
}
]
First, your columns have to use useMemo hooks. You can read the details here.
const columns = useMemo(() => [
...
],[])
Next, change the types property into subRows in your data so the subRows rows can be auto rendered and no additional subRow component required.
const data = [
{
id: "12345",
name: "sports",
subRows: [ // <---- change types into subRows
{
name: "basketball",
id: "1",
},
...
],
},
...
];
The subRows informations is also required to get the remaining items in heading. Here, we grab and describe the information at column's Cell
{
Header: () => <div />,
accessor: "name",
maxWidth: 300,
Cell: ({ row }) => {
// we can get subRows info here after change types into subRows
const { subRows } = row,
// describe the required information here
isSubRow = subRows[0] ? false : true,
firstSubRowName = subRows[0] ? subRows[0].original.name : "",
remainingSubRowsLength = subRows[1] ? `..+${subRows.length - 1}` : "";
return (
<span>
{row.original.name}
// conditionally render the additional info
{!isSubRow && (
<span
style={{ color: "blue" }}
>{` (${firstSubRowName}${remainingSubRowsLength})`}</span>
)}
</span>
);
}
}
And the final code will become:
import { useMemo } from "react";
import { useTable, useExpanded } from "react-table";
const data = [
{
id: "12345",
name: "sports",
subRows: [
{
name: "basketball",
id: "1"
},
{
name: "soccer",
id: "2"
},
{
name: "baseball",
id: "3"
}
]
},
{
id: "678910",
name: "food",
subRows: [
{
name: "pizza",
id: "4"
},
{
name: "hamburger",
id: "5"
},
{
name: "salad",
id: "6"
}
]
}
];
export default function App() {
const columns = useMemo(
() => [
{
Header: () => null,
id: "expander",
Cell: ({ row }) => {
return (
<span {...row.getToggleRowExpandedProps()}>
{row.depth === 0 && (row.isExpanded ? "▼" : "►")}
</span>
);
}
},
{
Header: () => <div />,
accessor: "name",
maxWidth: 300,
Cell: ({ row }) => {
const { subRows } = row,
isSubRow = subRows[0] ? false : true,
firstSubRowName = subRows[0] ? subRows[0].original.name : "",
remainingSubRowsLength = subRows[1] ? `..+${subRows.length - 1}` : "";
return (
<span>
{row.original.name}
{!isSubRow && (
<span
style={{ color: "blue" }}
>{` (${firstSubRowName}${remainingSubRowsLength})`}</span>
)}
</span>
);
}
}
],
[]
);
const { getTableProps, getTableBodyProps, rows, prepareRow } = useTable(
{
columns,
data
},
useExpanded
);
return (
<>
<h1>React Table v.7 SubRows</h1>
<br />
<table
{...getTableProps()}
style={{ borderCollapse: "collapse", width: "50%" }}
>
<tbody {...getTableBodyProps}>
{rows.map((row, index) => {
prepareRow(row);
return (
<tr
{...row.getRowProps}
key={index}
style={{
border: "1px solid black",
height: "30px",
background: row.subRows[0] ? "#e9ebfb" : "#fff"
}}
>
{row.cells.map((cell, i) => {
return (
<td {...cell.getCellProps()} key={i}>
{cell.render("Cell")}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
</>
);
}
Here is the example at codesanbox:
This code shows how to use a combobox in a Sharepoint online webpart using react. The sample data is hard coded. How can I bind the combo box to a Sharepoint list?
```
import * as React from 'react';
import { ComboBox, Fabric, IComboBoxOption, mergeStyles,
SelectableOptionMenuItemType, Toggle } from 'office-ui-fabric-
react/lib/index';
const INITIAL_OPTIONS: IComboBoxOption[] = [
{ key: 'Header1', text: 'First heading', itemType:
SelectableOptionMenuItemType.Header },
{ key: 'A', text: 'Option A' },
{ key: 'B', text: 'Option B' },
{ key: 'C', text: 'Option C' },
{ key: 'D', text: 'Option D' },
{ key: 'divider', text: '-',
itemType: SelectableOptionMenuItemType.Divider },
{ key: 'Header2', text: 'Second heading', itemType:
SelectableOptionMenuItemType.Header },
{ key: 'E', text: 'Option E' },
{ key: 'F', text: 'Option F', disabled: true },
{ key: 'G', text: 'Option G' },
{ key: 'H', text: 'Option H' },
{ key: 'I', text: 'Option I' },
{ key: 'J', text: 'Option J' }
];
const wrapperClassName = mergeStyles({
display: 'flex',
selectors: {
'& > *': { marginRight: '20px' },
'& .ms-ComboBox': { maxWidth: '300px' }
}
});
export interface IComboBoxTogglesExampleState {
autoComplete: boolean;
allowFreeform: boolean;
}
// tslint:disable:jsx-no-lambda
export class ComboBoxTogglesExample extends React.Component<{},
IComboBoxTogglesExampleState> {
public state: IComboBoxTogglesExampleState = {
autoComplete: false,
allowFreeform: true
};
public render(): JSX.Element {
const state = this.state;
return (
<Fabric className={wrapperClassName}>
<ComboBox
label="ComboBox with toggleable freeform/auto-complete"
key={'' + state.autoComplete + state.allowFreeform /*key causes re-
render when toggles change*/}
allowFreeform={state.allowFreeform}
autoComplete={state.autoComplete ? 'on' : 'off'}
options={INITIAL_OPTIONS}
/>
<Toggle
label="Allow freeform"
checked={state.allowFreeform}
onChange={(ev: React.MouseEvent<HTMLElement>, checked?: boolean) =>
{
this.setState({ allowFreeform: !!checked });
}}
/>
<Toggle
label="Auto-complete"
checked={state.autoComplete}
onChange={(ev: React.MouseEvent<HTMLElement>, checked?: boolean) =>
{
this.setState({ autoComplete: !!checked });
}}
/>
</Fabric>
);
}
}
```
This is for a Sharepoint Online webpart using the React Framework.
I have a list of 60 cost centers and I want them to appear in a combo box with autocomplete switched on.
Sample demo(many test scenarios, just checking the logic you need):
export interface IListItem{
Id: number;
Title: string;
Body : {
Body_p1: string;
Body_p2: string;
};
}
export interface IReactExState{
controlName:string,
ControlValue:string,
windowsID:number,
showPanel:boolean,
items: IListItem[],
Options:IComboBoxOption[],
selectionDetails: {},
showModal: boolean,
autoComplete: boolean,
allowFreeform: boolean
}
export default class OfficeFabric extends React.Component<IOfficeFabricProps, IReactExState> {
private _selection: Selection;
private _allItems: IListItem[];
private _columns: IColumn[];
public constructor(props: IOfficeFabricProps,state: IReactExState){
super(props);
this._selection = new Selection({
onSelectionChanged: () => this.setState({ selectionDetails: this._getSelectionDetails() })
});
this._allItems = [
{
Id : 0,
Title : "test0",
Body : {
Body_p1: "test0_p1",
Body_p2: "test0_p2"
},
},
{
Id : 1,
Title : "test1",
Body : {
Body_p1: "test1_p1",
Body_p2: "test1_p2"
}
}
];
this._columns = [
{ key: 'Id', name: 'Id', fieldName: 'Id', minWidth: 100, maxWidth: 200, isResizable: true },
{ key: 'Title', name: 'Title', fieldName: 'Title', minWidth: 200, maxWidth: 400, isResizable: true },
{ key: 'Body', name: 'Body', minWidth: 200, maxWidth: 400, isResizable: true,onRender: (item) => (
<div>
{item.Body.Body_p1}
</div>) },
];
this.state = {
controlName:"",
ControlValue:"",
windowsID:123.4,
showPanel:false,
items:this._allItems,
Options:[],
selectionDetails: this._getSelectionDetails() ,
showModal:false,
autoComplete: false,
allowFreeform: true
};
}
private _showModal = (): void => {
this.setState({ showModal: true });
};
private _closeModal = (): void => {
this.setState({ showModal: false });
};
private _getSelectionDetails(): string {
const selectionCount = this._selection.getSelectedCount();
switch (selectionCount) {
case 0:
return 'No items selected';
case 1:
return '1 item selected: ' + (this._selection.getSelection()[0] as IListItem).Title;
default:
return `${selectionCount} items selected`;
}
}
private _onItemInvoked = (item: IListItem): void => {
alert(`Item invoked: ${item.Title}`);
};
private _showPanel = () => {
this.setState({ showPanel: true });
};
private _hidePanel = () => {
this.setState({ showPanel: false });
};
private _Save = () => {
//to do save logic
this.setState({ showPanel: false });
alert('save clicked');
};
private _onRenderFooterContent = () => {
return (
<div>
<PrimaryButton onClick={this._hidePanel} style={{ marginRight: '8px' }}>
Save
</PrimaryButton>
<DefaultButton onClick={this._showPanel}>Cancel</DefaultButton>
</div>
);
};
public componentDidMount(){
var reactHandler = this;
this.props.context.spHttpClient.get(`${this.props.context.pageContext.web.absoluteUrl}/_api/web/lists/getbytitle('TestList')/items?select=ID,Title`,
SPHttpClient.configurations.v1) .then((response: SPHttpClientResponse) => {
response.json().then((responseJSON: any) => {
let tempOptions:IComboBoxOption[]=[];
responseJSON.value.forEach(element => {
tempOptions.push({key:element.ID,text:element.Title})
});
reactHandler.setState({
Options: tempOptions
});
});
});
}
// private _onJobTitReportToChange = (ev: React.FormEvent<HTMLInputElement>, newValue?: string) => {
// this.props.onJobTitleReportToChange(newValue);
// }
public handleObjectWithMultipleFields = (ev, newText: string): void => {
const target = ev.target;
const value = newText;
var _ControlName=target.name;
this.setState({
controlName: _ControlName,
ControlValue:value
})
}
public render(): React.ReactElement<IOfficeFabricProps> {
return (
<div className={ styles.officeFabric }>
<div className={ styles.container }>
<div className={ styles.row }>
<div className={ styles.column }>
<span className={ styles.title }>Welcome to SharePoint!</span>
<p className={ styles.subTitle }>Customize SharePoint experiences using Web Parts.</p>
<p className={ styles.description }>{escape(this.props.description)}</p>
<ComboBox
label="ComboBox with toggleable freeform/auto-complete"
key={'' + this.state.autoComplete + this.state.allowFreeform /*key causes re-
render when toggles change*/}
allowFreeform={this.state.allowFreeform}
autoComplete={this.state.autoComplete ? 'on' : 'off'}
options={this.state.Options}
/>
<TextField name="txtA" value={this.state.windowsID.toString()}
onChange={this.handleObjectWithMultipleFields}/>
<TextField name="txtB"
onChange={this.handleObjectWithMultipleFields}/>
<div>
<DefaultButton secondaryText="Opens the Sample Panel" onClick={this._showPanel} text="Open Panel" />
<Panel
isOpen={this.state.showPanel}
type={PanelType.smallFixedFar}
onDismiss={this._hidePanel}
headerText="Panel - Small, right-aligned, fixed, with footer"
closeButtonAriaLabel="Close"
onRenderFooterContent={this._onRenderFooterContent}
>
<DefaultButton className={styles.tablink} text="Button" />
<ChoiceGroup
options={[
{
key: 'A',
text: 'Option A'
},
{
key: 'B',
text: 'Option B',
checked: true
},
{
key: 'C',
text: 'Option C',
disabled: true
},
{
key: 'D',
text: 'Option D',
checked: true,
disabled: true
}
]}
label="Pick one"
required={true}
/>
</Panel>
<DefaultButton secondaryText="Opens the Sample Modal" onClick={this._showModal} text="Open Modal" />
</div>
<MarqueeSelection selection={this._selection}>
<DetailsList
items={this.state.items}
columns={this._columns}
setKey="set"
layoutMode={DetailsListLayoutMode.justified}
selection={this._selection}
selectionPreservedOnEmptyClick={true}
ariaLabelForSelectionColumn="Toggle selection"
ariaLabelForSelectAllCheckbox="Toggle selection for all items"
checkButtonAriaLabel="Row checkbox"
onItemInvoked={this._onItemInvoked}
/>
</MarqueeSelection>
<a href="https://aka.ms/spfx" className={ styles.button }>
<span className={ styles.label }>Learn more</span>
</a>
<Icon iconName='Mail' />
<br/>
<Icon iconName='CirclePlus' />
<br/>
<Icon iconName='LocationDot' />
</div>
</div>
</div>
</div>
);
}
}
I ended up using this.
sp.web.lists.getByTitle("ChartOfAccounts").items.getAll().then((result: any)=>{
for(let i: number = 0; i< result.length; i++) {
const b: SPData = result[i];
const c: IComboBoxOption={key:b.Column1, text: b.CostCentreInfo};
INITIAL_OPTIONS.push(c);
}
So, I am building an avatar creator for my application, and I have a Carousel that holds multiple RadioGroups, I can slide to the new radiogroup, but when I click on any of the other radio groups (except for the first one) and it will only target the value from the first one.
<Carousel options={{ fullWidth: true, indicators: true }} className="black-text center">
<div>
<RadioGroup
name="hair"
label="Hair Selection"
value={this.state.avatar.topType}
onChange={this.handleAvatarChange}
options={[{ label: 'Eyepatch', value: 'Eyepatch' }, { label: 'Long
Hair', value: 'LongHairStraight2' }, { label: 'Medium Hair', value:
'LongHairNotTooLong' }, { label: 'Short Hair', value:
'ShortHairShortFlat' }, { label: 'Short Dreads', value:
'ShortHairDreads01' }, { label: 'Balding', value: 'ShortHairSides'
}]}
/>
</div>
<div>
<RadioGroup
name="hairColor"
label="Hair Selection"
value={this.state.avatar.hairColor}
onChange={this.handleAvatarChange}
options={[{ label: 'Brown', value: 'Brown' }, { label: 'Blonde',
value: 'Blonde' }, { label: 'Red', value:
'Red' }, { label: 'Gray', value:
'Gray' }, { label: 'Black', value:
'Black' }, { label: 'Auburn', value: 'Auburn'
}]}
/>
</div>
</Carousel>
handleAvatarChange = (event) => {
let selection = event.target.value;
let type = event.target.name;
console.log(selection, 'event')
console.log(type, 'type');
let avatarCopy = { ...this.state.avatar };
if (type === 'hair') {
avatarCopy.topType = selection
this.setState({ avatar: avatarCopy });
} else if (type === 'hairColor') {
avatarCopy.hairColor = selection;
this.setState({ avatar: avatarCopy });
}
}
I expect that when I slide to the next slide on the carousel, that I can change the state based on the type that was passed back to my handleAvatarChange function. Instead, all of the slides are changing the values based on the first slide.
It seems like the autogenerated id numbering for the options resets to 0 for each radiogroup, even if they are in the same DOM.
Therefore, each n input of the radio groups has the same id (<input id="radio0" type="radio" value="1" checked="">).
I have reported the bug here.
As a workaround, I'm requesting an "id" prop, and if not found, concatenating the component's name to the index to build the id's.
var RadioGroup = function RadioGroup(_ref) {
var onChange = _ref.onChange,
withGap = _ref.withGap,
disabled = _ref.disabled,
name = _ref.name,
radioClassNames = _ref.radioClassNames,
value = _ref.value,
options = _ref.options;
return _react.default.createElement(_react.default.Fragment, null, options.map(function (radioItem, idx) {
return _react.default.createElement("label", {
className: radioClassNames,
htmlFor: radioItem.id ? radioItem.id : "radio".concat(radioItem.name).concat(idx),
key: radioItem.id ? radioItem.id : "radio".concat(radioItem.name).concat(idx)
}, _react.default.createElement("input", {
id: radioItem.id ? radioItem.id : "radio".concat(radioItem.name).concat(idx),
value: radioItem.value,
type: "radio",
checked: radioItem.value === value,
name: name,
onChange: onChange,
disabled: disabled,
className: (0, _classnames.default)({
'with-gap': withGap
})
}), _react.default.createElement("span", null, radioItem.label));
}));
};
Looking forward for any hint how to style new material ui v1 autocomplete or how to pass props to it.
Here's a codesandbox code (working example):
https://codesandbox.io/s/xrzq940854
In my particular case - I would like to style the label (which goes up after entering some value into input) and that horizontal line (underline under the input value).
Thank u for any help. (dropping code also in the snippet)
P.S. I got also a question how to pass props to the styles function. If anyone knows, please let me know :)
import React from 'react';
import PropTypes from 'prop-types';
import Autosuggest from 'react-autosuggest';
import match from 'autosuggest-highlight/match';
import parse from 'autosuggest-highlight/parse';
import TextField from 'material-ui/TextField';
import Paper from 'material-ui/Paper';
import { MenuItem } from 'material-ui/Menu';
import { withStyles } from 'material-ui/styles';
const suggestions = [
{ label: 'Afghanistan' },
{ label: 'Aland Islands' },
{ label: 'Albania' },
{ label: 'Algeria' },
{ label: 'American Samoa' },
{ label: 'Andorra' },
{ label: 'Angola' },
{ label: 'Anguilla' },
{ label: 'Antarctica' },
{ label: 'Antigua and Barbuda' },
{ label: 'Argentina' },
{ label: 'Armenia' },
{ label: 'Aruba' },
{ label: 'Australia' },
{ label: 'Austria' },
{ label: 'Azerbaijan' },
{ label: 'Bahamas' },
{ label: 'Bahrain' },
{ label: 'Bangladesh' },
{ label: 'Barbados' },
{ label: 'Belarus' },
{ label: 'Belgium' },
{ label: 'Belize' },
{ label: 'Benin' },
{ label: 'Bermuda' },
{ label: 'Bhutan' },
{ label: 'Bolivia, Plurinational State of' },
{ label: 'Bonaire, Sint Eustatius and Saba' },
{ label: 'Bosnia and Herzegovina' },
{ label: 'Botswana' },
{ label: 'Bouvet Island' },
{ label: 'Brazil' },
{ label: 'British Indian Ocean Territory' },
{ label: 'Brunei Darussalam' },
];
function renderInput(inputProps) {
const { classes, autoFocus, value, ref, ...other } = inputProps;
return (
<TextField
autoFocus={autoFocus}
className={classes.textField}
value={value}
inputRef={ref}
label="Country"
InputProps={{
classes: {
input: classes.input,
},
...other,
}}
/>
);
}
function renderSuggestion(suggestion, { query, isHighlighted }) {
const matches = match(suggestion.label, query);
const parts = parse(suggestion.label, matches);
return (
<MenuItem selected={isHighlighted} component="div">
<div>
{parts.map((part, index) => {
return part.highlight ? (
<span key={String(index)} style={{ fontWeight: 300 }}>
{part.text}
</span>
) : (
<strong key={String(index)} style={{ fontWeight: 500 }}>
{part.text}
</strong>
);
})}
</div>
</MenuItem>
);
}
function renderSuggestionsContainer(options) {
const { containerProps, children } = options;
return (
<Paper {...containerProps} square>
{children}
</Paper>
);
}
function getSuggestionValue(suggestion) {
return suggestion.label;
}
function getSuggestions(value) {
const inputValue = value.trim().toLowerCase();
const inputLength = inputValue.length;
let count = 0;
return inputLength === 0
? []
: suggestions.filter(suggestion => {
const keep =
count < 5 && suggestion.label.toLowerCase().slice(0, inputLength) === inputValue;
if (keep) {
count += 1;
}
return keep;
});
}
const styles = theme => ({
container: {
flexGrow: 1,
position: 'relative',
height: 200,
},
suggestionsContainerOpen: {
position: 'absolute',
marginTop: theme.spacing.unit,
marginBottom: theme.spacing.unit * 3,
left: 0,
right: 0,
},
suggestion: {
display: 'block',
},
suggestionsList: {
margin: 0,
padding: 0,
listStyleType: 'none',
},
textField: {
width: '100%',
},
label: {
color: 'yellow',
}
});
class IntegrationAutosuggest extends React.Component {
state = {
value: '',
suggestions: [],
};
handleSuggestionsFetchRequested = ({ value }) => {
this.setState({
suggestions: getSuggestions(value),
});
};
handleSuggestionsClearRequested = () => {
this.setState({
suggestions: [],
});
};
handleChange = (event, { newValue }) => {
this.setState({
value: newValue,
});
};
render() {
const { classes } = this.props;
return (
<Autosuggest
theme={{
container: classes.container,
suggestionsContainerOpen: classes.suggestionsContainerOpen,
suggestionsList: classes.suggestionsList,
suggestion: classes.suggestion,
}}
renderInputComponent={renderInput}
suggestions={this.state.suggestions}
onSuggestionsFetchRequested={this.handleSuggestionsFetchRequested}
onSuggestionsClearRequested={this.handleSuggestionsClearRequested}
renderSuggestionsContainer={renderSuggestionsContainer}
getSuggestionValue={getSuggestionValue}
renderSuggestion={renderSuggestion}
inputProps={{
autoFocus: true,
classes,
placeholder: 'Search a country (start with a)',
value: this.state.value,
onChange: this.handleChange,
}}
/>
);
}
}
IntegrationAutosuggest.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(IntegrationAutosuggest);
Material-UI v1 uses React-autosuggest module.
Check the below link
https://github.com/moroshko/react-autosuggest/blob/master/src/Autosuggest.js