I inherited a Kendo React subclass from a colleague. The subclass name is FormDropDownList
.
It is a basic combination of a Label
and a DropDownList
The value of the drop-down doesn't seem to get reflected in the Form values on submit.
Any ideas why?
Test Harness:
import * as React from "react";
import * as ReactDOM from "react-dom";
import { Field, Form, FormElement } from "@progress/kendo-react-form";
import { FormDropDownList } from "./FormDropDownList";
const handleSubmit1 = (dataItem) => {
alert(JSON.stringify(dataItem));
};
const AppComponent = () => {
const moduleData = [
{
description: 'Alpha',
module: 1
},
{
description: 'Beta',
module: 2
}
];
return (
<Form
onSubmit={handleSubmit1}
render={(formRenderProps) => (
<FormElement>
Name:
<Field name="firstName" label="First name"
component="input" />
<div className={"k-form-field-wrap"}>
<Field label={'Module'}
name={'module'}
id={'module'}
required={true}
dataItemKey={"module"}
textField={"description"}
data={moduleData}
dropdownType={false}
component={FormDropDownList} />
</div>
<button type={"submit"} disabled={false}>
Submit
</button>
</FormElement>
)}
/>
);
};
ReactDOM.render(<AppComponent />, document.querySelector("my-app"));
Custom component:
import * as React from "react";
import { FieldWrapper } from "@progress/kendo-react-form";
import { Label, Error, Hint } from "@progress/kendo-react-labels";
import { DropDownList } from "@progress/kendo-react-dropdowns";
import axios from "axios";
export const FormDropDownList = (fieldRenderProps) => {
const {
validationMessage,
touched,
label,
id,
valid,
disabled,
hint,
wrapperStyle,
dropdownType,
data,
value,
name,
style,
...others
} = fieldRenderProps;
const {
onChange,
dataItemKey,
textField,
extra_param,
extra_param_name
} = others;
const [state, setState] = React.useState([]);
const [currentValue, setCurrentValue] = React.useState({});
const loadDefaultData = (props) => {
var cData = {};
cData = props.find((obj) => obj[dataItemKey] === value);
setCurrentValue(cData);
};
const onValueChange = (event) => {
var cData = event.target.value; // selected data Object
setCurrentValue(cData);
};
/**
* Populate list
*/
React.useEffect(() => {
setState(data);
loadDefaultData(data);
}, []);
const editorRef = React.useRef(null);
const showValidationMessage = touched && validationMessage;
const showHint = !showValidationMessage && hint;
const hintId = showHint ? `${id}_hint` : "";
const errorId = showValidationMessage ? `${id}_error` : "";
const labelId = label ? `${id}_label` : "";
return (
<FieldWrapper style={wrapperStyle}>
<Label
id={labelId}
editorRef={editorRef}
editorId={id}
editorValid={valid}
editorDisabled={disabled}
>
{label}
</Label>
<DropDownList
onChange={onValueChange}
ariaLabelledBy={labelId}
ariaDescribedBy={`${hintId} ${errorId}`}
ref={editorRef}
valid={valid}
id={id}
name={name}
value={currentValue}
disabled={disabled}
data={state}
dataItemKey={dataItemKey}
textField={textField}
style={style}
/>
{showHint && <Hint id={hintId}>{hint}</Hint>}
{showValidationMessage && <Error id={errorId}>{validationMessage}</Error>}
</FieldWrapper>
);
};
The value of the drop-down doesn't seem to get reflected in the Form values on submit. Any ideas why?
You are getting the kendo-react-form onChange
method here:
const {
onChange,
dataItemKey,
textField,
extra_param,
extra_param_name
} = others;
The onChange
declared here ( = others.onChange
) is the function that updates the value for the submit. However your are sending onValueChange
to the DropDownList
<DropDownList
onChange={onValueChange}
And the onValueChange
function doesn't call the onChange
method from the kendo-react-form
anywhere (so the form values are not changing in any way, since you are only setting a local state. This is basically why value of the drop-down doesn't get reflected in the Form values on submit)
Potential fix
You shouldn't need any state in FormDropDownList
, but rather just send the default props provided by the form to the dropdown. So something like:
import * as React from "react";
import { FieldWrapper } from "@progress/kendo-react-form";
import { Label, Error, Hint } from "@progress/kendo-react-labels";
import { DropDownList } from "@progress/kendo-react-dropdowns";
import axios from "axios";
export const FormDropDownList = (fieldRenderProps) => {
const {
validationMessage,
touched,
label,
hint,
wrapperStyle,
dropdownType,
extra_param,
extra_param_name
...others
} = fieldRenderProps;
const editorRef = React.useRef(null);
const showValidationMessage = touched && validationMessage;
const showHint = !showValidationMessage && hint;
const hintId = showHint ? `${id}_hint` : "";
const errorId = showValidationMessage ? `${id}_error` : "";
const labelId = label ? `${id}_label` : "";
return (
<FieldWrapper style={wrapperStyle}>
<Label
id={labelId}
editorRef={editorRef}
editorId={id}
editorValid={valid}
editorDisabled={disabled}
>
{label}
</Label>
{/* the props that are not explicitly defined bellow
will be transmitted trough {...others} part (ex: value, data, etc.) */}
<DropDownList
ariaLabelledBy={labelId}
ariaDescribedBy={`${hintId} ${errorId}`}
ref={editorRef}
{...others}
/>
{showHint && <Hint id={hintId}>{hint}</Hint>}
{showValidationMessage && <Error id={errorId}>{validationMessage}</Error>}
</FieldWrapper>
);
};
Please note the above example is for giving you a hint and it might need small adjustments (without a minimal reproducible example I was not able to fully test your code and therefore neither this one.)
However the option with {...others} should work. You can also check a reproducible example with Kendo React DropDownList
and the {...others}
approach here