Mantine: how to combine use-form with Select and numbers - reactjs

I want to build a form that can be used to manage an option that is stored in the database as a number.
However, if I now enter the item from the database into the hook:
const form = useForm({.
initialValues: {
option: 1
},
});
Is this not compatible with the Select component, because it works internally only with strings. So in this case the correct value is not selected:
<Select
label="Option"
{...form.getInputProps("option")}
/>
Now how can I solve this problem in an elegant way? Is there an API/option for this or do I really need to manually convert each numeric value into a string to make this compatible with Mantine?
Thanks a lot.

The code below should be self explanatory. If not, please read the #mantine/form package documentation.
import { Select } from "#mantine/core";
import { useForm } from "#mantine/form";
const data = [
{ value: "", label: "Select an option", disabled: true },
{ value: "1", label: "Option 1" },
{ value: "2", label: "Option 2" },
];
export default function MyForm() {
// create a form with initial values (field: value map)
// that match the `value`s defined in `data:
const form = useForm({
initialValues: {
status: "",
},
});
// create form submit handler:
const formOnSubmit = form.onSubmit(
(values) => console.log(values),
// optional, as form.getInputProps() can make inputs display the error themselves:
(errors) => console.error(errors)
);
return (
<form onSubmit={formOnSubmit}>
<Select
label="Status"
placeholder="Status"
data={data}
{...form.getInputProps("status")}
/>
<Group position="right" mt="md">
<Button type="submit">Submit</Button>
</Group>
</form>
);
}

I believe you can fix this by casting the type of the "value".
This is undocumented, and potentially could break with future releases, but you can do this:
import { Select } from "#mantine/core";
import { useForm } from "#mantine/form";
const data = [
{ value: '', label: 'Select' },
{ value: 2 as any, label: 'New' } // <-- here's the magic
];
export default function MyForm() {
const form = useForm({
initialValues: {
status: ''
},
});
return (
<form onSubmit={form.onSubmit((values) => console.log(values))}>
<Select label="Status" placeholder="Status"
data={data}
{...form.getInputProps('status')} />
<Group position="right" mt="md">
<Button type="submit">Submit</Button>
</Group>
</form>
);
}
I assume that what's happening inside the Select ultimately is some equality checks that will pass with numbers just as well as strings, so you get the correct item selected when it renders, and the correct value out when it submits.
I personally use this with a zodResolver that would complain bitterly about providing strings where it expects a number, and I'm loathe to make my zod schemas more complex to handle this problem.
To be fair, I can appreciate Mantine taking the approach of only supporting strings, since native HTML <select /> elements will always give you strings, and opening the door to anything else is probably a lot of work.
Still, seems like just providing the number value, and keeping typescript happy with as any (or you could do as unknown as string if you're not into the whole brevity thing) works a treat - at least for now!

I use this code:
import { Select } from "#mantine/core";
import { useForm } from "#mantine/form";
const data = [
{ value: '', label: 'Select' },
{ value: 2, label: 'New' }
];
export default function MyForm() {
const form = useForm({
initialValues: {
status: ''
},
});
return (
<form onSubmit={form.onSubmit((values) => console.log(values))}>
<Select label="Status" placeholder="Status"
data={data}
{...form.getInputProps('status')} />
<Group position="right" mt="md">
<Button type="submit">Submit</Button>
</Group>
</form>
);
}

Related

React-select fills an null value option when I try to update a created object

I'm using react-select for choosing members for a project based on a team list.
The format of the options is as specified in the docs (array of objects with label and value)
const options = [
{label: "Sam Altman", value: "61b5b1a4f401d574f5cefab7"},
{label: "Sam B", value: "87tgb1a4f401d574f5cefab7"},
{label: "John Altman", value: "9o2nb1a4f401d574f5sd347"},
]
The problem arises when I'm trying to update the values in a different view. The selected values contains null option (where I auto populate the form with the created values)
My current select component is as follows: -
<Select
isMulti
options={options}
value={item}
onChange={(newMembers) =>
setValues({ ...values, assignedTo: newMembers || [] })
}
/>
The problem only arises while updating the created members
use values instead of value. below is sample code.
import { useState } from 'react';
import Select from 'react-select';
const options = [
{ label: "Sam Altman", value: "61b5b1a4f401d574f5cefab7" },
{ label: "Sam B", value: "87tgb1a4f401d574f5cefab7" },
{ label: "John Altman", value: "9o2nb1a4f401d574f5sd347" }
];
function App() {
const [values, setVaues] = useState([]);
return (
<div>
<Select
isMulti
values={values}
onChange={(newMembers) => setVaues({ ...values, assignedTo: newMembers || [] })} options={options}
/>
</div>
);
}
export default App;

React-select defaultValue is not showing

I'm using Formik and React-select library and defaultValue is not working/taking effect and it remains empty, i don't know why this is happening.
MySelectInput component:
interface Props {
// .. other props
options: CategoryOptions[];
defaultCategory: CategoryOptions;
}
const MySelectInput: React.FC<Props> = (props) => {
const [field, meta, helpers] = useField(props.name);
return (
<>
<Select
options={props.options}
isSearchable
defaultValue={props.defaultCategory}
onChange={(v) => helpers.setValue(v!.value)}
onBlur={() => helpers.setTouched(true)}
placeholder={props.placeholder}
styles={customSelectStyles}
/>
</>
)
};
export default MySelectInput;
Usage:
<MySelectInput
options={CategoryOptions}
placeholder="Category"
name="category"
label="Category"
defaultCategory={{ value: activity.category, label: activity.category }}
/>
My array of objects (CategoryOptions):
export const CategoryOptions: CategoryOptions[] = [
{ value: 'drinks', label: 'Drinks' },
{ value: 'music', label: 'Music' },
{ value: 'travel', label: 'Travel' },
];
The options are working and displaying well but defaultValue is not working. If i use static strings inside object properties like:
defaultCategory={{ value: "test", label: "test" }}
is working well. Any idea?
I think you should probably use an item from CategoryOptions.
Instead of
defaultValue={props.defaultCategory}
do
defaultValue={props.defaultCategory[0]}
I'm also wondering why your CategoryOptions object is same as the CategoryOptions type. Maybe you should rename it to categoryOptions

React combo doesnt select proper value

I'm totally new in react and I am trying to create add/edit form with combo box in it. I saved data in database but now when I loaded the form there is no selected value in "bank" combo. Looks like combo gets default value "Select" and I don't know where is the problem. My .net backend returns proper bank id from database and company.bankId also has value.
interface IProps {
closeAddEditCompanyModal: any,
cancelClick: any,
saveClick: any,
isVisible: boolean,
currentCompany: CompanyModel,
}
interface IState {
company: CompanyModel;
validationMessage: string,
isLoading: boolean,
activeIndex: number;
selectedIndex: number;
banks: Array<BankModel>;
isVisibleAddEditBankDialog: boolean;
}
handleChangeSelect = (key, e) => {
const company: CompanyModel = { ...this.state.company};
company[key] = e.value;
this.setState({ company: { ...company } });
};
<div style={{ minHeight: '50px' }}>
<FormControl>
<InputLabel htmlFor="active-label">Banks</InputLabel>
<Select
name="bankId"
options={this.state.banks.map( bank => ({
value: bank.bankId,
label: bank.bankName
}))}
onChange={(e) => this.handleChangeSelect('bankId', e)}
value={company && company.bankId ? company.bankId : ''}
>
</Select>
</FormControl>
import { useState } from "react";
import Select from "react-select";
function App() {
const [companyId, setCompanyId] = useState();
const letterChange = (data) => {
console.log(data);
company[data.value] = data.value;
// you can do here whatever you wish to do
// setCompanyId(data);
};
const banks = [
{ value: "bank1", label: "bank1" },
{ value: "bank2", label: "bank2" },
{ value: "bank3", label: "bank3" },
{ value: "bank4", label: "bank4" },
{ value: "bank5", label: "bank5" },
{ value: "bank6", label: "bank6" },
{ value: "bank7", label: "bank7" },
];
const company = [{
bank1: { value: "company1", label: "company1" },
bank2: { value: "company2", label: "company2" },
}];
return (
<>
<div className="App">
<Select
name="bankId"
options={banks}
onChange={letterChange}
value={companyId}
></Select>
</div>
</>
);
}
export default App;
I am still not clear what you are trying to achieve here. But here is a small piece of snippet that might help you.
Couple of things that i would like to point out in your code.
Inside your onChange handleChangeSelect you are passing a hardcoded value by passing bankId as string. I don't know if thats intentional.
You don't have to loop through the array inside options. Rather you can just pass the whole array itself.
This is just a suggestion but if you are already using material ui package you can use the select from material ui itself. This is just to avoid using extra packages unless and until there is a need for it.

How to display multiple selected values from a dropdown in React

I'm new to React and I wanted to create a dropdown which can select multiple values. For that I used the react-select plugin. In my React dev tool the selected values are getting stored but I'm not able to display all the selected values.
Any help is highly appreciated.
TIA
import React, { useState } from "react";
import Select from 'react-select'
const options = [
{ value: 'React', label: 'React' },
{ value: 'Vue', label: 'Vue' },
{ value: 'Angular', label: 'Angular' },
{ value: 'Java', label: 'Java' },
]
const [skills, setSkills] = useState([]);
const handleChange = (skill) => {
setSkills({skill})
console.log("skills", skill);
}
return (
<>
<h2>Please select all your skills</h2>
<form>
<Select
options={options}
onChange={handleChange}
isMulti={true}
value={value}
/>
<button>Next</button>
</form>
</>
)
}
export default UserSkills;
When I'm commenting isMulti prop, I'm getting that one selected value, but I'm not getting anything with isMulti prop.
You are controlling the Select component by giving it a value, and since you are not updating value in the handleChange function it will not be updated.
You could use the skills array as value instead and it will update as expected.
CodeSandbox
const options = [
{ value: "React", label: "React" },
{ value: "Vue", label: "Vue" },
{ value: "Angular", label: "Angular" },
{ value: "Java", label: "Java" }
];
function UserSkills() {
const [skills, setSkills] = useState([]);
const handleChange = (skills) => {
setSkills(skills || []);
};
return (
<>
<h2>Please select all your skills</h2>
<form>
<Select
options={options}
onChange={handleChange}
value={skills}
isMulti
/>
<button>Next</button>
</form>
</>
);
}
export default UserSkills;

send form values from child function component to parent class component

I've learned that it's best to minimize the number of class components and to keep all the logic in as few components as possible. I've managed to create a to-do list that only has the 1 class component by putting this in the input tag of the SearchBar component:
onChange={e => props.updateVal(e.target.value)}
That does exactly what I want and sends that 1 piece of data back to the parent's updateVal function.
What I want to figure out is how to do this with 1 form submit that contains several inputs which are all text fields. Is it even possible? I'd like to stay away from refs and changing the component to a class. This is just practice for me as I get better at react and any insights would be appreciated.
Focus on making reusable components that can be used throughout your application.
For example, you can create your own reusable input:
import React from 'react';
// props will consist of "value", "onChange", "name" and a "placeholder"
const Input = props => <input type="text" {...props} />
export default Input;
Now create a container that handles all of the input's values;
import React, { Component } from 'react';
import Input from '../Input';
const fields = [
{
name: "company",
placeholder: "Company"
},
{
name: "email",
placeholder: "Email"
},
{
name: "firstName",
placeholder: "First Name"
},
{
name: "lastName",
placeholder: "First Name"
},
];
class Form extends Component {
state = { firstName: "", lastName: "", email: "", company: "" };
handleChange = ({ target: {name, value} }) => this.setState({ [name]: value });
handleSubmit = e => {
e.preventDefault();
alert(JSON.stringify(this.state, null, 4));
}
render = () => (
<form onSubmit={this.handleSubmit}>
{fields.map(props => <Input key="props.name" onChange={this.handleChange} {...props} /> )}
<button type="submit">Submit</button>
</form>
);
};
export default Form;
Working example (one class component and one reusable component -- click Run code snippet):
const Input = props => <input type="text" {...props} />
const fields = [
{ name: "company", placeholder: "Company" },
{ name: "email", placeholder: "Email" },
{ name: "firstName", placeholder: "First Name" },
{ name: "lastName", placeholder: "First Name" }
];
class Form extends React.Component {
state = { firstName: "", lastName: "", email: "", company: "" };
handleChange = ({ target: {name, value} }) => this.setState({ [name]: value });
handleSubmit = e => {
e.preventDefault();
alert(JSON.stringify(this.state, null, 4));
}
render = () => (
<form onSubmit={this.handleSubmit}>
{fields.map(props => <Input key="props.name" onChange={this.handleChange} {...props}/>)}
<button type="submit">Submit</button>
</form>
);
};
ReactDOM.render(<Form />, document.body);
<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>
You could take it a step further and make the Form reusable; although, it'll be harder to maintain as the form gets more complex with different inputs, field-level validations, and field styling.
I'd suggest learning how to utilize classes before you start jumping into the up-and-coming hooks.
My suggestion is to use Redux-form with react for better form handling ,
LIbrary Reference - Redux Form
Watch This Tech Talk - Before Click Reference

Resources