getting error Dropdown `value` must be an array when `multiple` is set. Received type: `[object String]` - javascript

I am getting this error while using multiselect with final-form.
Dropdown value must be an array when multiple is set. Received
type: [object String]
here is my code:
https://codesandbox.io/s/cool-torvalds-lhe9d
<Dropdown
{...props.input}
clearable
fluid
multiple
search
onChange={(e, data) => {
return data.value.length > 0
? input.onChange(data.value)
: input.onChange("");
}}
onSearchChange={onSearchChange}
selection
defaultValue={[]}
options={data}
placeholder="Select values"
/>
any update?

You need to remove defaultValue prop and pass value prop as [] if value is not available to Dropdown component.
const SingleSelectAutoComplete = props => {
const renderError = ({ error, touched }, id) => {
if (touched && error) {
return <div id={id}>{error}</div>;
}
};
const {
input,
label,
onSearchChange,
data,
meta,
required,
onChange,
helloWorld
} = props;
console.log("***********************");
let { value, ...restProps } = props.input;
const id = input.name;
return (
<div
className={`field ${meta.error && meta.touched ? " error" : ""} ${
required ? " required" : ""
}`}
>
<label>{label}</label>
<Dropdown
{...restProps}
value={value || []}
clearable
fluid
multiple
search
onChange={(e, data) => {
return data.value.length > 0
? input.onChange(data.value)
: input.onChange("");
}}
onSearchChange={onSearchChange}
selection
options={data}
placeholder="Select values"
/>
{renderError(meta, `${id}-error-text`)}
</div>
);
};

Related

How to set props value as selected checked in dropdown

I am creating a dropdown edit form where on edit user will able to see the option value as selected from props on edit. I tried with defaultValue and using selected but it seems my conditions are wrong.
Any suggestions which I can utilized to check the props value in option and display as selected on dropdown when user click edit.
Here selectedPropsName is what we are getting from props and I want to map and display this as selected.
Thanks...
Code
const results = [
{
'Name': 'apple',
'description': 'apple is good for health'
},
{
'Name': 'mango',
'description': 'mango is very juicy'
}
]
const props = {
'Name': 'apple'
}
const CreateForm=()=> {
const [spaceName, setSpaceName] = React.useState('');
const [, setSpaceDescriptionName] = React.useState('');
const handleChangeSpaceName = (event: React.ChangeEvent<HTMLInputElement>) => {
setSpaceName(event.target.value);
setSpaceDescriptionName(event.target.value)
};
const selectedPropsName = props.Name
return (
<>
<div className='create-dropdown'>
<TextField
className='create-textfield'
id='create-textfield'
select={true}
label='create Name'
value={spaceName}
onChange={handleChangeSpaceName}
SelectProps={{
native: true,
}}
variant='standard'
>
{results && results.length > 0 && results.map((optionNames:any) => (
<option key={optionNames.Name}
className='textfield-option'
value={`${optionNames.Name}, ${optionNames.description}`}>
{optionNames.Name}
</option>
))}
</TextField>
</div>
</>
)
}
If I understand you correctly, you should be able to check if optionNames.Name equals selectedPropsName and then set the option's selected attribute to true, conditionally.
So,
{results && results.length > 0 && results.map((optionNames:any) => (
<option key={optionNames.Name}
className='textfield-option'
value={`${optionNames.Name}, ${optionNames.description}`}>
{optionNames.Name}
</option>
))}
becomes
{results && results.length > 0 && results.map((optionNames:any) => (
<option key={optionNames.Name}
selected={optionNames.Name === selectedPropsName ? true : false}
className='textfield-option'
value={`${optionNames.Name}, ${optionNames.description}`}>
{optionNames.Name}
</option>
))}
EDIT:
My mistake. I've taken another look. It looks like you are using Material-UI and so, the select component is controlled. You would have to set the initial value through the spaceName hook. And you would have to change the props.Name variable to include a "name, description" since that is what your option value={} field is expecting. So, these changes should make it work:
const props = {
Name: "mango, mango is very juicy",
};
const [spaceName, setSpaceName] = React.useState(props.Name);

select upto 3 in category list from array in list in react.js

I am working in react, fixed-sized array but I am not getting output when I am select up to 3 record but it show only 1 record select.
CODE:
this.state = {
type: [3], //select upto 3 record(type select from category)
categoryList: null, // category-list
};
changeCategory(o){
this.setState({type: o})
}
<div>
{ categoryList.map((o,index)=>{
return <div key={index} className={"rounded " + (type==o.slug ?"selected" : '')} onClick={()=>this.changeCategory(o.slug)} style={{padding: "2px 5px"}}>{o.name}</div>
})
}
</div>
ISSUE
type is a state array and you are comparing it like the value in the render method. In this way, you always have just one item selected instead of 3 items.
SOLUTION
This code will help you to select 3 items
this.state = {
type: [],
....
};
// this will add selected item in `type` array if length not exceed
changeCategory(o){
if(type.length !== 3){ // for limit of 3
const newType = [...this.state.type];
newType.push(o.slug);
this.setState({type: newType});
}
}
<div>
{categoryList.map((o, index) => {
return (
<div
key={index}
className={
"rounded " + (this.state.type.includes(o.slug) ? "selected" : "")
}
onClick={() => this.changeCategory(o.slug)}
style={{ padding: "2px 5px" }}
>
{o.name}
</div>
);
})}
</div>

Unable to show helperText once we click on the Submit button using reactjs?

I'm new to this dropdown validations, i want to show helpertext bottom of the dropdown when the dropdown field is selected (or) we have selected but again selected the -1 menu item value. Here I'm facing few issues.
Couldn't able to show red color for helpertext.
For me, it is showing error in line #50 but in Sandbox it is not showing any error.
While submitting form with empty dropdown field(-1) then it should show helpertext.
I could not able to show the Helper Text while submitting the form.
Here i have tried in this way:
class Sample extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
channel: -1,
sports: -1,
movie: ""
};
}
handleChange = (e: any) => {
this.setState({ channel: e.target.value });
};
handleSports = (e: any) => {
this.setState({ sports: e.target.value });
};
handleMovie = (e: any) => {
this.setState({ movie: e.target.value });
};
Valid = () => {
const errors = { channel: "", sports: "", movie: "" };
if (!this.state.channel) {
errors.channel = "Please select channel";
}
if (!this.state.sports) {
errors.sports = "select Sports";
}
if (!this.state.movie) {
errors.movie = "select movie";
}
return {
errors,
isSubmit: Object.keys(errors).length === 0
};
};
handleSubmit = (e: any) => {
e.preventDefault();
const data = {
channel: this.state.channel,
sports: this.state.sports,
movie: this.state.movie
};
console.log(data);
};
render() {
const { errors, isSubmit } = this.Valid();
return (
<>
<FormControl>
<Select
defaultValue={-1}
onChange={this.handleChange}
displayEmpty
inputProps={{ "aria-label": "Without label" }}
>
<MenuItem value={-1}>Select Channel</MenuItem>
<MenuItem value={10}>Sports</MenuItem>
<MenuItem value={20}>Entertainment</MenuItem>
</Select>
{!this.state.channel ? (
<FormHelperText>{errors.channel}</FormHelperText>
) : null}
</FormControl>
{this.state.channel === 10 ? (
<div>
<FormControl>
<Select
defaultValue={-1}
onChange={this.handleSports}
displayEmpty
inputProps={{ "aria-label": "Without label" }}
>
<MenuItem value={-1}>Select </MenuItem>
<MenuItem value={10}>Star sports 1</MenuItem>
<MenuItem value={20}>Star sports 2</MenuItem>
</Select>
{!this.state.sports ? (
<FormHelperText>{errors.sports}</FormHelperText>
) : null}
</FormControl>
</div>
) : this.state.channel === 20 ? (
<div>
<FormControl>
<Select
defaultValue={-1}
onChange={this.handleMovie}
displayEmpty
inputProps={{ "aria-label": "Without label" }}
>
<MenuItem value={-1}>Select</MenuItem>
<MenuItem value={10}>Star Movies</MenuItem>
<MenuItem value={20}>ABC</MenuItem>
</Select>
{!this.state.movie ? (
<FormHelperText>{errors.movie}</FormHelperText>
) : null}
</FormControl>
</div>
) : null}
<div>
<Button disabled={isSubmit} onClick={this.handleSubmit}>
Submit
</Button>
</div>
</>
);
}
}
export default Sample;
Here is the sample
Can anyone please help me with this query?
Issue 1
Couldn't able to show red color for helpertext.
You can color the text red by using the error prop on the FormControl or FormHelperText. The FormControl actually provides a context to the fields it wraps so it's easiest to set the error prop there.
<FormControl error={!!errors?.channel}>
...
{errors?.channel && <FormHelperText>{errors.channel}</FormHelperText>}
</FormControl>
Issue 2
For me, it is showing error in line #50 but in Sandbox it is not
showing any error.
Unfortunately without any more context about what line 50 consists of locally for you there's not much to resolve here. Feel free to update your question with more details, perhaps a code snippet of the offending line and the copy of the error message.
Issue 3
While submitting form with empty dropdown field(-1) then it should
show helpertext.
Here I think a bit of a refactor is in order.
Disable the first "placeholder" select option, it should really be selectable, but it can still be the defaultValue. What this means is that once a valid option is selected, only other valid options can be selected, it can never select the disabled option. This also means that the field is only invalid while a user has not chosen any option.
<MenuItem disabled value={-1}>
Select Channel
</MenuItem>
<MenuItem value={10}>Sports</MenuItem>
<MenuItem value={20}>Entertainment</MenuItem>
You've 2 levels of select fields. When a user changes the root channel state, reset the movie and sports states.
Change the state shape to include some error/validation object that will hold errors and form submittable status. Reset when state updates.
componentDidUpdate(prevProps, prevState) {
// If channel updated then reset "nested" select values
if (prevState.channel !== this.state.channel) {
this.setState({
sports: null,
movie: null
});
}
// Clear error state upon change, next validation to occur next submit attempt
if (!prevState.validation.canSubmit && !this.state.validation.canSubmit) {
this.setState({
validation: {
canSubmit: true
}
});
}
}
Add name attributes to the select inputs to be accessed in the onChange handlers; these should match the names in state. Also, because you have a name, you can reduce the onChange handlers down to a single input change handler.
<Select
defaultValue={-1}
onChange={this.handleChange}
displayEmpty
inputProps={{ "aria-label": "Without label" }}
name="channel" // <-- add name attribute (add for other inputs as well)
>
handler
handleChange = (e: any) => {
const { name, value } = e.target;
this.setState({ [name]: value } as Pick<
State,
"channel" | "movie" | "sports"
>);
};
Since it isn't possible to select sports AND movie, use some branching logic to validate one or the other depending on channel, i.e. if sports is expected to have a value then movie will never have a value, and vice-versa.
Valid = ({ channel, sports, movie }): Validation => {
const errors: Errors = {};
if (!channel) {
errors.channel = "Please select channel";
} else {
if (channel === 10) {
if (!sports) {
errors.sports = "select Sports";
}
} else {
if (!movie) {
errors.movie = "select movie";
}
}
}
return {
errors,
canSubmit: !Object.keys(errors).length
};
};
Move the form validation to the onSubmit handler, disable the submit button if the validation "canSubmit" status is false.
handleSubmit = (e: any) => {
e.preventDefault();
const { channel, movie, sports } = this.state;
const validation = this.Valid({ channel, movie, sports });
if (validation.canSubmit) {
window.alert("SUBMIT!!");
} else {
console.log("errors", validation.errors);
this.setState({ validation });
}
};
Fullcode
I'll apologize ahead of time as I have very little to no typescript experience. Just some quick reading up on syntax. The following has zero errors/warnings in the linked sandbox.
import React from "react";
import {
FormControl,
Select,
MenuItem,
FormHelperText,
Button
} from "#material-ui/core";
interface Props {}
interface Errors {
channel?: string;
sports?: string;
movie?: string;
}
interface Validation {
errors?: Errors;
canSubmit: boolean;
}
interface State {
channel: number;
sports: number;
movie: string;
validation: Validation;
}
class Sample extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
channel: null,
sports: null,
movie: null,
validation: {
canSubmit: true
}
};
}
componentDidUpdate(prevProps, prevState) {
// If channel updated then reset "nested" select values
if (prevState.channel !== this.state.channel) {
this.setState({
sports: null,
movie: null
});
}
// Clear error state upon change, next validation to occur next submit attempt
if (!prevState.validation.canSubmit && !this.state.validation.canSubmit) {
this.setState({
validation: {
canSubmit: true
}
});
}
}
handleChange = (e: any) => {
const { name, value } = e.target;
this.setState({ [name]: value } as Pick<
State,
"channel" | "movie" | "sports"
>);
};
Valid = ({ channel, sports, movie }): Validation => {
const errors: Errors = {};
if (!channel) {
errors.channel = "Please select channel";
} else {
if (channel === 10) {
if (!sports) {
errors.sports = "select Sports";
}
} else {
if (!movie) {
errors.movie = "select movie";
}
}
}
return {
errors,
canSubmit: !Object.keys(errors).length
};
};
handleSubmit = (e: any) => {
e.preventDefault();
const { channel, movie, sports } = this.state;
const validation = this.Valid({ channel, movie, sports });
if (validation.canSubmit) {
window.alert("SUBMIT!!");
} else {
console.log("errors", validation.errors);
this.setState({ validation });
}
};
render() {
const {
validation: { canSubmit, errors }
} = this.state;
return (
<>
<FormControl error={!!errors?.channel}>
<Select
defaultValue={-1}
onChange={this.handleChange}
displayEmpty
inputProps={{ "aria-label": "Without label" }}
name="channel"
>
<MenuItem disabled value={-1}>
Select Channel
</MenuItem>
<MenuItem value={10}>Sports</MenuItem>
<MenuItem value={20}>Entertainment</MenuItem>
</Select>
{errors?.channel && <FormHelperText>{errors.channel}</FormHelperText>}
</FormControl>
{this.state.channel === 10 && (
<div>
<FormControl error={!!errors?.sports}>
<Select
defaultValue={-1}
onChange={this.handleChange}
displayEmpty
inputProps={{ "aria-label": "Without label" }}
name="sports"
>
<MenuItem disabled value={-1}>
Select{" "}
</MenuItem>
<MenuItem value={10}>Star sports 1</MenuItem>
<MenuItem value={20}>Star sports 2</MenuItem>
</Select>
{errors?.sports && (
<FormHelperText>{errors.sports}</FormHelperText>
)}
</FormControl>
</div>
)}
{this.state.channel === 20 && (
<div>
<FormControl error={!!errors?.movie}>
<Select
defaultValue={-1}
onChange={this.handleChange}
displayEmpty
inputProps={{ "aria-label": "Without label" }}
name="movie"
>
<MenuItem disabled value={-1}>
Select
</MenuItem>
<MenuItem value={10}>Star Movies</MenuItem>
<MenuItem value={20}>ABC</MenuItem>
</Select>
{errors?.movie && (
<FormHelperText error>{errors.movie}</FormHelperText>
)}
</FormControl>
</div>
)}
<div>
<Button disabled={!canSubmit} onClick={this.handleSubmit}>
Submit
</Button>
</div>
</>
);
}
}
export default Sample;

Autocomplete Set Default Value in React

I need to have a default value in my autocomplete in my react app. My problem is when i try to submit it, it still is invalid. Meaning it has no value in it. I need to click the autocomplete and select it again just to make to have the value.
Pls check this codesandbox link CLICK HERE
<Autocomplete
name="member_status"
value={values.member_status}
options={memberStatuses ? memberStatuses : []}
getOptionLabel={(memberStatus) => memberStatus.name}
onChange={(e, value) => {
setFieldValue(
"member_status",
value !== null ? value.id : ""
);
}}
renderInput={(params) => (
<TextField
{...params}
label="Member Status"
name="member_status"
variant="outlined"
onBlur={handleBlur}
helperText={
touched.member_status ? errors.member_status : ""
}
error={
touched.member_status && Boolean(errors.member_status)
}
/>
)}
/>
The issue here is you are setting the initial value of your Autocomplete as an object, then you're validating for a string.
Changing your validationSchema to
const validationSchema = yup.object().shape({
member_status: yup
.object()
.shape({
id: yup.number(),
name: yup.string()
})
.nullable()
.required("Select member status")
});
and your Autocomplete's onChange handler to
...
onChange={(e, value) => {
setFieldValue("member_status", value); // set the new value to an object, not string
}}
should work.

React Components utilization

I am trying to use the following component in my file, but cannot format options as the component would like. New to this... any ideas on how to fix my code would be greatly appreciated.
Field below the componenet is how I'm trying to use it.
/**
* Single select dropdown component
* - Uses an array passed to options prop
* - 'options' Array must have 'value' (what is submitted) & 'text'
(what is displayed)
*/
export class SingleSelect extends React.Component {
render () {
const {
input,
label,
options,
required,
placeholder,
meta: { error, warning, touched },
...props
} = this.props;
let message;
const validationState = touched && ( error && 'error' ) || ( warning && 'warning' ) || null;
if ( touched && ( error || warning ) ) {
message = <span className="help-block">{ error || warning }</span>;
}
let placeholderText = 'Select an option';
if ( placeholder ) {
placeholderText = placeholder;
}
const asterisk = required && (<span className="form-field-required" />) || null;
return (
<FormGroup validationState={ validationState }>
<ControlLabel>
{ label }
{ asterisk }
</ControlLabel>
<FormControl {...{
...input,
componentClass: 'select',
placeholder: placeholderText,
...props
}} >
<option value="">{ placeholderText }</option>
{
options.map((option, index) => (
<option key={index} value={option.value}>
{option.text}
</option>
))
}
</FormControl>
{ message }
<FormControl.Feedback />
</FormGroup>
);
}
}
<Field
name="type"
label="Type"
component={fields.SingleSelect}
options={
text=[Media File, External File]
value=type
}
required
placeholder
validate={[validators.required]}
/>
You need extra {} around the object you are passing:
<Field
name="type"
label="Type"
component={fields.SingleSelect}
options={[{
text: 'Media File'
value: type
},{
text: 'External File'
value: type
}]}
required
placeholder
validate={[validators.required]}
/>
In JSX, the first {} indicate that what's inside is JavaScript that needs to be ran. So you can kind of think about the first {} being ignored.

Categories

Resources