I actually have a drag and drop list from BaseWeb https://baseweb.design/components/dnd-list/,
And instead of havings strings as the exemple shows, i'm having components for a blog, like a text section, some inputs, etc... I use this list to reorder my components easily, but i got a problem, if i want to click to go in my text input, I drag my component, and don't get in.
I'm using React-Quill for the text editor
Here's my code for the list:
initialState={{
items: componentsArray
}}
onChange={({oldIndex, newIndex}) =>
setComponentsArray(newIndex === -1 ?
arrayRemove(componentsArray, oldIndex) :
arrayMove(componentsArray, oldIndex, newIndex))
}
className=""
overrides={{
DragHandle: <FontAwesomeIcon icon={Icons.faLeftRight} />,
}}
/>
Try cancel onmousedown BaseWeb's handler for elements you need to free of drag.
import React, { useState, useEffect, useRef } from 'react';
import { List, arrayMove } from 'baseui/dnd-list';
import { StatefulSelect } from 'baseui/select';
import { v4 as uuidv4 } from 'uuid';
const RulesTab = () => {
const [items, setItems] = useState([{ id: uuidv4() }, { id: uuidv4() }]);
const dndRootRef = useRef(null);
useEffect(() => {
// override base-web's mousedown event handler
dndRootRef.current.addEventListener('mousedown', (el) => {
let isFreeOfDrag = false;
let currentEl = el.target;
// check if the element you clicked is inside the "free-of-drag block"
do {
if (currentEl.getAttribute('test-id') === 'free-of-drag') {
isFreeOfDrag = true;
break;
} else {
currentEl = currentEl.parentElement;
}
} while (currentEl);
// invoke el.stopPropagation(); if the element you clicked is inside the "free-of-drag block"
if (isFreeOfDrag) {
el.stopPropagation();
}
});
}, []);
return (
<List
items={items.map(({ id }, index) => (
<div style={{ display: 'flex' }} test-id="free-of-drag" key={id}>
<StatefulSelect
options={[
{ label: 'AliceBlue', id: '#F0F8FF' },
{ label: 'AntiqueWhite', id: '#FAEBD7' },
]}
placeholder="Select color"
/>
</div>
))}
onChange={({ oldIndex, newIndex }, el) => setItems(arrayMove(items, oldIndex, newIndex))}
overrides={{
Root: {
props: {
ref: dndRootRef,
},
},
}}
/>
);
};
Related
I'm currently stuck on trying to display the number of correct answers once the quiz is finished.
Basically, I have created a state that keeps track of the number of correct answers shown within the QuizItem component. If the user selected answer matches the correct answer, then the user selected answer turns to green and it will increase the state of correctCount (as seen in the code) to 1. This new value is then passed to the parent component of QuizItem which is QuizList.
/* eslint-disable react/prop-types */
import React from "react";
import AnswerButton from "../UI/AnswerButton";
import classes from "./QuizItem.module.css";
export default function QuizItem(props) {
const [correctCount, setCorrectCount] = React.useState(0)
function addToCorrectCount() {
setCorrectCount(correctCount + 1)
}
props.onSaveCorrectCountData(correctCount)
console.log(correctCount);
return (
<div>
<div key={props.id} className={classes.quizlist__quizitem}>
<h3 className={classes.quizitem__h3}>{props.question}</h3>
{props.choices.map((choice) => {
const styles = {
backgroundColor: choice.isSelected ? "#D6DBF5" : "white",
};
// React.useEffect(() => {
// if (choice.isSelected && choice.choice === choice.correct) {
// addToCorrectCount();
// }
// }, [choice.isSelected, choice.correct]);
function checkAnswerStyle() {
/* this is to indicate that the selected answer is right, makes button go green*/
if (choice.isSelected && choice.choice === choice.correct) {
addToCorrectCount()
return {
backgroundColor: "#94D7A2",
color: "#4D5B9E",
border: "none",
};
/* this is to indicate that the selected answer is wrong, makes button go red*/
} else if (choice.isSelected && choice.choice !== choice.correct) {
return {
backgroundColor: "#F8BCBC",
color: "#4D5B9E",
border: "none",
};
/* this is to highlight the right answer if a selected answer is wrong*/
} else if (choice.choice === choice.correct) {
return {
backgroundColor: "#94D7A2",
color: "#4D5B9E",
border: "none",
};
/* this is to grey out the incorrect answers*/
} else {
return {
color: "#bfc0c0",
border: "1px solid #bfc0c0",
backgroundColor: "white",
};
}
}
return (
<AnswerButton
key={choice.id}
onClick={() => {
props.holdAnswer(choice.id);
}}
style={props.endQuiz ? checkAnswerStyle() : styles}
>
{choice.choice}
</AnswerButton>
);
})}
</div>
</div>
);
}
// create a counter, and for every correct answer (green button), increase the counter by 1.
In the QuizList component, I have set another state to receive the incoming value from the QuizItem component and use this new value to display the number of correct answers once the check answers button has been clicked.
import React from "react";
import { nanoid } from "nanoid";
import QuizItem from "./QuizItem";
import Button from "../UI/Button";
import Card from "../UI/Card";
import classes from "./QuizList.module.css";
export default function QuizList(props) {
const [quiz, setQuiz] = React.useState([]);
const [endQuiz, setEndQuiz] = React.useState(false);
// const [newGame, setNewGame] = React.useState(false);
const [noOfCorrectAnswers, setNoOfCorrectAnswers] = React.useState()
function addCorrectCountHandler(correctCount) {
setNoOfCorrectAnswers(correctCount)
}
React.useEffect(() => {
/* This function turns HTML element entities into normal words */
function decodeHtml(html) {
const txt = document.createElement("textarea");
txt.innerHTML = html;
return txt.value;
}
fetch(
"https://opentdb.com/api.php?amount=5&category=9&difficulty=medium&type=multiple"
)
.then((res) => res.json())
.then((data) => {
const dataArray = data.results;
const newDataArray = dataArray.map((item) => {
return {
question: decodeHtml(item.question),
choices: [
{
choice: decodeHtml(item.correct_answer),
isSelected: false,
correct: decodeHtml(item.correct_answer),
id: nanoid(),
},
{
choice: decodeHtml(item.incorrect_answers[0]),
isSelected: false,
correct: decodeHtml(item.correct_answer),
id: nanoid(),
},
{
choice: decodeHtml(item.incorrect_answers[1]),
isSelected: false,
correct: decodeHtml(item.correct_answer),
id: nanoid(),
},
{
choice: decodeHtml(item.incorrect_answers[2]),
isSelected: false,
correct: decodeHtml(item.correct_answer),
id: nanoid(),
},
].sort(() => 0.5 - Math.random()),
id: nanoid(),
};
});
return setQuiz(newDataArray);
});
}, []);
// console.log(quiz);
function finishQuiz() {
setEndQuiz((prevEndQuiz) => !prevEndQuiz);
}
// function startNewGame() {
// setNewGame(true);
// }
function holdAnswer(quizId, choiceId) {
setQuiz((oldQuiz) =>
oldQuiz.map((quiz) => {
if (quiz.id !== quizId) return quiz;
return {
...quiz,
choices: quiz.choices.map((choice) =>
choice.id === choiceId
? // If the choice selected is the current choice, toggle its selected state
{ ...choice, isSelected: !choice.isSelected }
: // Otherwise, deselect the choice
{ ...choice, isSelected: false }
),
};
})
);
}
const quizItemComponents = quiz.map((item) => {
return (
<QuizItem
key={item.id}
question={item.question}
choices={item.choices}
holdAnswer={(id) => holdAnswer(item.id, id)}
endQuiz={endQuiz}
correct={quiz.correct}
onSaveCorrectCountData={addCorrectCountHandler}
/>
);
});
return (
<Card className={classes.quizlist}>
{quizItemComponents}
{!endQuiz && <Button onClick={finishQuiz}>Check Answers</Button>}
{endQuiz && (
<div className={classes.result}>
<p>You scored {noOfCorrectAnswers}/5 answers</p>
<Button onClick={startNewGame}>Play Again</Button>
</div>
)}
</Card>
);
}
The error that I was getting is that there were too many re-renders, so I tried using useEffect on the setCorrectCount state within my QuizItem component (this can be seen in my code and greyed out) but it would not tally up the count.
Is there a good workaround to this problem? Any help or advice would be appreciated.
Link to the code via Stackblitz:
https://stackblitz.com/edit/quizzical
I'm trying to show the active side navigation items in Shopify Polaris Navigation components.
Here I have tried in few ways, problem is when I'm clicking nav items 2 times then showing the currently active nav link!
Can you suggest me better efficient code to solve this problem? If any more dynamic solutions available please suggest!
import React, { Fragment, useState } from "react";
import { Frame, Navigation, Page } from "#shopify/polaris";
import { GiftCardMinor } from "#shopify/polaris-icons";
import { useNavigate } from "react-router-dom";
const LeftNavigation = ({ pageTitle, loading, children }: any) => {
const [selected, setSelected] = useState([false, false]);
const navigate = useNavigate();
const handleSelect = (index) => {
// const newFilter = [...selected];
// newFilter.fill(false, 0, newFilter.length);
// newFilter[index] = true;
// setSelected(newFilter);
const newArray = selected.map((item, itemIndex) => {
return itemIndex === index
? (selected[index] = true)
: (selected[itemIndex] = false);
});
setSelected(newArray);
};
return (
<Fragment>
<Frame
navigation={
<div style={{ marginTop: "4rem" }}>
<Navigation location="/">
<Navigation.Section
title="nav items"
items={[
{
label: "one",
icon: icon1,
selected: selected[0],
onClick: () => {
handleSelect(0);
navigate("/one");
},
},
{
label: "two",
icon: icon2,
selected: selected[1],
onClick: () => {
handleSelect(1);
navigate("/two");
},
},
]}
/>
</Navigation>
</div>
}
></Frame>
</Fragment>
);
};
export default LeftNavigation;
In order to make the "active" state more dynamic it should probably only store the id of the active menu item. When mapping/rendering the menu items check explicitly against the current state value. The onClick handler should pass the currently clicked-on item's "id" value to the callback handler.
Example using the "target path" as the id value*:
const LeftNavigation = ({ pageTitle, loading, children }: any) => {
const [selected, setSelected] = useState<string | null>(null);
const navigate = useNavigate();
const handleSelect = (selectedId) => {
setSelected(selected => selected === selectedId ? null : selectedId);
};
return (
<Fragment>
<Frame
navigation={
<div style={{ marginTop: "4rem" }}>
<Navigation location="/">
<Navigation.Section
title="nav items"
items={[
{
label: "one",
icon: icon1,
selected: selected === "/one",
onClick: () => {
handleSelect("/one");
navigate("/one");
},
},
{
label: "two",
icon: icon2,
selected: selected === "/two",
onClick: () => {
handleSelect("/two");
navigate("/two");
},
},
]}
/>
</Navigation>
</div>
}
></Frame>
</Fragment>
);
};
*Note: the id value can be anything, but you should ensure it's unique per menu item if you want up to only one active at-a-time.
I am trying to create a list of buttons with values that are stored in a state and user is only allowed to use 1 item (I dont want to use radio input because I want to have more control over styling it).
import React from "react";
import { useEffect, useState } from "react";
import "./styles.css";
const items = [
{ id: 1, text: "Easy and Fast" },
{ id: 2, text: "Easy and Cheap" },
{ id: 3, text: "Cheap and Fast" }
];
const App = () => {
const [task, setTask] = useState([]);
const clickTask = (item) => {
setTask([...task, item.id]);
console.log(task);
// how can I make sure only 1 item is added to task
// and remove the other items
// only one option is selectable all the time
};
const chosenTask = (item) => {
if (task.find((v) => v.id === item.id)) {
return true;
}
return false;
};
return (
<div className="App">
{items.map((item) => (
<li key={item.id}>
<label>
<button
type="button"
className={chosenTask(item) ? "chosen" : ""}
onClick={() => clickTask(item)}
onChange={() => clickTask(item)}
/>
<span>{item.text}</span>
</label>
</li>
))}
</div>
);
};
export default App;
https://codesandbox.io/s/react-fiddle-forked-cvhivt?file=/src/App.js
I am trying to only allow 1 item to be added to the state at all the time, but I dont know how to do this?
Example output is to have Easy and Fast in task state and is selected. If user click on Easy and Cheap, select that one and store in task state and remove Easy and Fast. Only 1 item can be in the task state.
import React from "react";
import { useEffect, useState } from "react";
import "./styles.css";
const items = [
{ id: 1, text: "Easy and Fast" },
{ id: 2, text: "Easy and Cheap" },
{ id: 3, text: "Cheap and Fast" }
];
const App = () => {
const [task, setTask] = useState();
const clickTask = (item) => {
setTask(item);
console.log(task);
// how can I make sure only 1 item is added to task
// and remove the other items
// only one option is selectable all the time
};
return (
<div className="App">
{items.map((item) => (
<li key={item.id}>
<label>
<button
type="button"
className={item.id === task?.id ? "chosen" : ""}
onClick={() => clickTask(item)}
onChange={() => clickTask(item)}
/>
<span>{item.text}</span>
</label>
</li>
))}
</div>
);
};
export default App;
Is this what you wanted to do?
Think of your array as a configuration structure. If you add in active props initialised to false, and then pass that into the component you can initialise state with it.
For each task (button) you pass down the id, and active state, along with the text and the handler, and then let the handler in the parent extract the id from the clicked button, and update your state: as you map over the previous state set each task's active prop to true/false depending on whether its id matches the clicked button's id.
For each button you can style it based on whether the active prop is true or false.
If you then need to find the active task use find to locate it in the state tasks array.
const { useState } = React;
function Tasks({ config }) {
const [ tasks, setTasks ] = useState(config);
function handleClick(e) {
const { id } = e.target.dataset;
setTasks(prev => {
// task.id === +id will return either true or false
return prev.map(task => {
return { ...task, active: task.id === +id };
});
});
}
// Find the active task, and return its text
function findSelectedItem() {
const found = tasks.find(task => task.active)
if (found) return found.text;
return 'No active task';
}
return (
<section>
{tasks.map(task => {
return (
<Task
key={task.id}
taskid={task.id}
active={task.active}
text={task.text}
handleClick={handleClick}
/>
);
})};
<p>Selected task is: {findSelectedItem()}</p>
</section>
);
}
function Task(props) {
const {
text,
taskid,
active,
handleClick
} = props;
// Create a style string using a joined array
// to be used by the button
const buttonStyle = [
'taskButton',
active && 'active'
].join(' ');
return (
<button
data-id={taskid}
className={buttonStyle}
type="button"
onClick={handleClick}
>{text}
</button>
);
}
const taskConfig = [
{ id: 1, text: 'Easy and Fast', active: false },
{ id: 2, text: 'Easy and Cheap', active: false },
{ id: 3, text: 'Cheap and Fast', active: false }
];
ReactDOM.render(
<Tasks config={taskConfig} />,
document.getElementById('react')
);
.taskButton { background-color: palegreen; padding: 0.25em 0.4em; }
.taskButton:not(:first-child) { margin-left: 0.25em; }
.taskButton:hover { background-color: lightgreen; cursor: pointer; }
.taskButton.active { background-color: skyblue; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>
I am working with ReactJS and using Semantic UI.
I have a breadcrumb style navigation menu on my page built using the 'Breadcrumb' and 'Dropdown' components from Semantic UI.
I am trying to make the behaviour of the menu accessible by allowing the user to use the keyboard (tab, arrows and enter) to navigate the menu, the dropdown options and to make a selection from the dropdown options.
The issue I am trying to solve is when using the keyboard, the user should only be able to select an option when it is focused on (using the arrow keys) followed by pressing the 'enter' key. At the moment when the user focuses on an option, it gets selected when they 'tab' to the next element.
Is it possible to change this behaviour so an option is only selected when the enter key is pressed?
I tried implementing "selectOnNavigation={false}" on the Dropdown component however this still results in the option being selected when 'tabbing' away from the element.
I also tried manipulating the event handler onBlur() but it still selected the option when tabbing.
Code for my component:
import React from 'react';
import { connect } from 'react-redux';
import { Breadcrumb, Dropdown } from 'semantic-ui-react';
import PropTypes from 'prop-types';
import {
saveBreadcrumbOptions,
changeBreadcrumbMarket,
changeBreadcrumbParentGroup,
changeBreadcrumbAgency
} from '../../actions/breadcrumbActions';
import MenuFiltersAPI from '../../api/MenuFiltersAPI';
import './OMGBreadcrumb.css';
export class OMGBreadcrumb extends React.Component {
constructor(props) {
super(props);
this.state = {
markets: [],
parentGroups: [],
agencies: []
};
this.getBreadcrumbOptions = this.getBreadcrumbOptions.bind(this);
this.handleMarketChange = this.handleMarketChange.bind(this);
this.handleParentGroupChange = this.handleParentGroupChange.bind(this);
this.handleAgencyChange = this.handleAgencyChange.bind(this);
this.handleParentGroupBlur = this.handleParentGroupBlur.bind(this);
}
componentDidMount() {
this.getBreadcrumbOptions();
}
async getBreadcrumbOptions() {
// get all options
const breadcrumb = this.props.breadcrumb.options.length
? this.props.breadcrumb.options
: await MenuFiltersAPI.getBreadcrumb();
// if a market is selected, use it
// otherwise use the first one
let selectedMarket = breadcrumb.find(m => (
m.id === this.props.breadcrumb.selectedMarket
));
selectedMarket = selectedMarket
? selectedMarket.id
: breadcrumb[0].id;
this.props.saveBreadcrumbOptions(breadcrumb);
this.setState({ markets: breadcrumb }, () => this.changeMarket(selectedMarket));
}
changeMarket(id) {
// get parent group options for given market
const parentGroups = this.state.markets.find(market => market.id === id).parent_groups;
// if a parent group is selected, use it
// otherwise use the first one
let selectedParentGroup = parentGroups.find(pg => (
pg.id === this.props.breadcrumb.selectedParentGroup
));
selectedParentGroup = selectedParentGroup
? selectedParentGroup.id
: parentGroups[0].id;
this.props.changeBreadcrumbMarket(id);
this.setState({ parentGroups }, () => this.changeParentGroup(selectedParentGroup));
}
changeParentGroup(id) {
// get agency options for dropdown menu
const agencies = this.state.parentGroups.find(parentGroup => parentGroup.id === id).agencies;
let selectedAgency = agencies.find(a => (
a.id === this.props.breadcrumb.selectedAgency
));
selectedAgency = selectedAgency
? selectedAgency.id
: agencies[0].id;
this.props.changeBreadcrumbParentGroup(id);
this.setState({ agencies }, () => this.changeAgency(selectedAgency));
}
changeAgency(id) {
// const selectedAgency = agencyOptions[0].value
this.props.changeBreadcrumbAgency(id);
}
handleMarketChange(e, { value }) {
console.log(value)
this.changeMarket(value);
}
handleParentGroupChange(e, { value }) {
console.log(value)
// if(!!value){
// return;
// }
this.changeParentGroup(value);
}
handleAgencyChange(e, { value }) {
console.log(value)
this.changeAgency(value);
}
handleParentGroupBlur(e, {value}) {
e.preventDefault();
console.log(e.key)
if(e.key !== 'Enter'){
console.log('key was not enter')
return;
}
}
render() {
return (
<div id="OMGBreadcrumb">
<b>Show information by: </b>
<Breadcrumb>
<Breadcrumb.Section>
<Dropdown
selectOnNavigation={false}
options={this.state.markets.reduce((acc, cur) => {
acc.push({ text: cur.name, value: cur.id });
return acc;
}, [])}
value={this.props.breadcrumb.selectedMarket}
onChange={this.handleMarketChange}
openOnFocus={false}
/>
</Breadcrumb.Section>
<Breadcrumb.Divider icon='right chevron' />
<Breadcrumb.Section>
<Dropdown
selectOnNavigation={false}
options={this.state.parentGroups.reduce((acc, cur) => {
acc.push({ text: cur.name, value: cur.id });
return acc;
}, [])}
value={this.props.breadcrumb.selectedParentGroup}
onChange={this.handleParentGroupChange}
openOnFocus={false}
onBlur={this.handleParentGroupBlur}
/>
</Breadcrumb.Section>
<Breadcrumb.Divider icon='right chevron' />
<Breadcrumb.Section>
<Dropdown
// selectOnNavigation={false}
options={this.state.agencies.reduce((acc, cur) => {
acc.push({ text: cur.name, value: cur.id });
return acc;
}, [])}
value={this.props.breadcrumb.selectedAgency}
onChange={this.handleAgencyChange}
openOnFocus={false}
/>
</Breadcrumb.Section>
</Breadcrumb>
</div>
);
}
}
OMGBreadcrumb.propTypes = {
saveBreadcrumbOptions: PropTypes.func.isRequired,
changeBreadcrumbMarket: PropTypes.func.isRequired,
changeBreadcrumbParentGroup: PropTypes.func.isRequired,
changeBreadcrumbAgency: PropTypes.func.isRequired,
breadcrumb: PropTypes.objectOf(
PropTypes.oneOfType([
PropTypes.number,
PropTypes.array
])
).isRequired
};
export default connect(
store => ({
breadcrumb: store.breadcrumb
}),
{
saveBreadcrumbOptions,
changeBreadcrumbMarket,
changeBreadcrumbParentGroup,
changeBreadcrumbAgency
}
)(OMGBreadcrumb);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Appreciate any guidance.
You can add selectOnBlur={false} to your dropdown component and it will no longer select when the dropdown is blurred.
<Dropdown
...
selectOnBlur={false}
/>
https://codesandbox.io/s/semantic-ui-example-7qgcu?module=%2Fexample.js
I've created this cool sandbox that utilises react-select and the creatable feature. It allows you to select from a prepopulated dropdown and at the same time create a custom option by typing into the select field. Once you have typed into the field your option becomes available in the select list.
I have added in options to be grouped - pre-existing fields are fine, but new options I would like to be grouped by a default value e.g. "new group".
Any help would be appreciated.
https://codesandbox.io/s/p5x7m478rm
import React from "react";
import { Field, reduxForm, FieldArray } from "redux-form";
import TextField from "material-ui/TextField";
import { RadioButton, RadioButtonGroup } from "material-ui/RadioButton";
import Checkbox from "material-ui/Checkbox";
import SelectField from "material-ui/SelectField";
import MenuItem from "material-ui/MenuItem";
import asyncValidate from "./asyncValidate";
import validate from "./validate";
import CreatableSelect from "react-select/lib/Creatable";
const CustomStyle = {
option: (base, state) => ({
...base,
display: "inline",
marginRight: "10px",
backgroundColor: state.isSelected ? "#00285C" : "#eee",
cursor: "pointer"
}),
menuList: () => ({
padding: 10,
display: "inline-flex"
}),
menu: () => ({
position: "relative"
})
};
const createOption = (label: string) => ({
label,
value: label.toLowerCase().replace(/\W/g, "")
});
const formatGroupLabel = data => (
<div>
<span>{data.label}</span>
</div>
);
class LastNameSelectInput extends React.Component {
constructor(props) {
super(props);
}
state = {
value: this.props.options[0].options,
options: this.props.options
};
handleCreate = input => (inputValue: any) => {
this.setState({ isLoading: true });
setTimeout(() => {
const { options, value } = this.state;
const newOption = createOption(inputValue);
this.setState({
isLoading: false,
options: [...options, newOption],
value: newOption,
formatGroupLabel: "new label"
});
input.onChange(newOption);
}, 1000);
};
isValidNewOption = (inputValue, selectValue, selectOptions) => {
if (
inputValue.trim().length === 0 ||
selectOptions.find(option => option.name === inputValue)
) {
return false;
}
return true;
};
render() {
const { input, options } = this.props;
return (
<div>
<style>
{`.react-select__dropdown-indicator,.react-select__indicator-separator {
display: none;
}`}
</style>
<CreatableSelect
classNamePrefix="react-select"
options={this.state.options}
menuIsOpen={true}
onChange={value => {
let newValue = input.onChange(value);
this.setState({ value: newValue });
}}
onBlur={() => input.onBlur(input.value)}
onCreateOption={this.handleCreate(input)}
value={this.state.value}
styles={CustomStyle}
isClearable
isValidNewOption={this.isValidNewOption}
formatGroupLabel={formatGroupLabel}
/>
</div>
);
}
}
const MaterialUiForm = props => {
const { handleSubmit, options, pristine, reset, submitting } = props;
return (
<form onSubmit={handleSubmit}>
<div>
<Field name="option" component={LastNameSelectInput} {...props} />
</div>
</form>
);
};
export default reduxForm({
form: "MaterialUiForm", // a unique identifier for this form
validate,
asyncValidate
})(MaterialUiForm);
To achieve your goal I have changed the function handleCreate you have provided and the options props. You can see a live example here.
In MaterialUiForm.js
handleCreate = input => (inputValue: any) => {
this.setState({ isLoading: true });
setTimeout(() => {
const { options } = this.state;
const newOption = createOption(inputValue);
options.map(option => {
if (option.label === "New group") {
return {
label: option.label,
options: option.options.push(newOption)
};
}
return option;
});
this.setState({
isLoading: false,
options: [...options],
value: newOption,
formatGroupLabel: "new label"
});
input.onChange(newOption);
}, 1000);
In index.js
<MaterialUiForm
onSubmit={showResults}
initialValues={{
option: colourOptions,
option: flavourOptions
}}
options={[
{
label: "New group",
options: []
},
{
label: "Colours",
options: colourOptions
},
{
label: "Flavours",
options: flavourOptions
}
]}
/>
There is different and probably smarter way to do it but the logic is the good one.