redux-form and react-select onChange doesn't update redux value - javascript

So I'm having issues using redux-form with react-select, this is what I have so far:
<Field
name="objective"
type="text"
component={prop => <FormSelect {...prop} options={options} />}
label="Objective"
/>
And then:
const FormSelect = ({ options, label, input: { value, onChange, onBlur } }) =>
<ControlGroup title={label} styleId={label}>
<Select
options={options}
simpleValue
onChange={onChange}
value={value}
onBlur={() => onBlur(value)}
id={label}
/>
</ControlGroup>;
But then the select value does not change..
I get a redux-form/CHANGE with a action.payload of awareness (which is the value I want to select), but right after there is another redux-form action redux-form/BLUR with an action.payload of "".
I've read a bunch of github issues about this, tried a lot of them but nothing seems to be working..
example:
https://github.com/JedWatson/react-select/issues/1129
https://github.com/erikras/redux-form/issues/82
I also tried: onBlur={() => onBlur('awareness')} and it did not change the value on the select, even both payloads were had the same value..

I forgot to add redux-form reducer to my reducers.. Thanks anyway

Related

React Formik autocomplete='on' on form in nested fields

I have encountered an issue which does not seem solvable at the moment. I implemented Formik to solve Reacts autocomplete on controlled inputs but it does not work as expected.
The issue is on submit autocomplete values are not saved in the browser.
For example:
name="object.email" does not work (for providing email autocomplete), same as object.name and so on for standard field names
Has anyone encountered this and is there a fix or do I have to live with it?
I have tried adding autocomplete keys to inputs but that does not work either.
My form has autocomplete='on' but that just does not seem to do anything at the moment and submit event does not capture the form values at all
This is how my input component looks like:
const Input: React.FC<IInputProps> = ({
label,
value,
onChange,
id,
name,
placeholder,
className,
onBlur,
type = 'text',
maxLength,
hasAutocomplete
}) => {
return (
<label htmlFor={id} className={clsx('input', className)}>
<div className='input__label'>{label}</div>
<input
id={id}
name={name}
className='input__input'
value={value}
onChange={onChange}
onBlur={onBlur}
placeholder={placeholder}
type={type}
maxLength={maxLength}
max={maxLength}
autoComplete={hasAutocomplete ? name : 'off'}
/>
</label>
)
}

How to prevent react-final-form from rendering an specific input

I have a react-final-form form, which has 2 inputs. Let's call them from and to.
What I want to do is that whenever input from changes, I set a value for input to based on input from's value.
I do that in validate function because i don't know where else i can do that. And it causes re-rendering the component in a loop.
Since I change the value of to in validate, it causes validate function to run again and again and again. How can I avoid that?
The actual code is much more complex than this but this is where i run into problems.
Thanks
const validate = (v) => {
const calculateFrom = calculate(v.from);
window.setTo(calculateFrom);
};
<Form
onSubmit={onSubmit}
validate={validate}
mutators={{
setTo: (a, s, u) => {
u.changeValue(s, 'to', () => a[0]);
},
setMax: (a, s, u) => {
u.changeValue(s, 'from', () => getMaxBalance(selectedAsset1));
},
}}
subscription={{ submitting: true, pristine: true }}
render={({
form,
pristine,
invalid,
handleSubmit,
}) => {
if (!window.setTo) {
window.setTo = form.mutators.setTo;
}
return (
<form onSubmit={handleSubmit}>
<Field name="from">
{({ input, meta }) => (
<Input
type="number"
placeholder="123"
size="input-medium"
input={input}
meta={meta}
/>
)}
</Field>
<Field name="to">
{({ input, meta }) => (
<Input
type="number"
placeholder="123"
size="input-medium"
input={input}
meta={meta}
/>
)}
</Field>
/>
First of all you could use an existing decorator
https://codesandbox.io/s/oq52p6v96y
I'm not really sure why it is re-rendering infinitely. Might have something to do with reusing the function setTo that you put on the window.
If you don't want to add that mutator library I'd try the following solutions.
use parse prop on the the Field where you can get the value and compare it with the other value that you need and return exactly what is should be check attached example parse prop
Final form allows to nest Fields inside custom components so you could just handle everything there by using useForm hook

Input unfocus after typing something in it, i put an onChange function that sets a state using setstate(react hooks) (TextField material ui)

When using a setting a state((useState() / setState()), the input unfocuses, idk why?
pls help
React hook State
const [username, setUsername] = useState("");
this is the my own component which returns a textfield but with my own styles
function FormInput({ onChange, ...rest }) {
const classes = formInputStyles();
return (
<div>
<TextField
onChange={(e) => onChange(e.target.value)}
InputProps={{ classes, disableUnderline: true }}
{...rest}
/>
</div>
);
}
Like, i said in the title whenever i type something in the input field it unfocuses and clears the input field.
It dosen't unfocus when i use the normal < TextField > from material ui.
i tried making a whole new function for setting state but that didnt work
<FormInput
onChange={(value) => {
setUsername(value);
}}
label="Username"
variant="filled"
></FormInput>

React setState side effects with Form Data

Sorry for the general title but I don't know what else to call it at this point. I have a form that uses widgets. Im using the react-jsonschema-form package. Id use the github for the project but I don't think this is bug so I want to check here first. I think it's just how to use this React thing question. Possibly Redux as well.
So...
I have these widgets for some of the form elements in my component.
dropdownWidget = (props, type, id) => {
return (
<div>
<input id={id} type="text" className="form-control" list={type} placeholder="Select one..." onChange={(event) => { props.onChange(event.target.value); this.hideResultTables(event.target.id) }} />
<datalist id={type}>
{this.props.actionsObj.filterJsonData(type, this.props.convertDropDownDataObj).map((value, index) => { return <option key={index} value={value}>{value}</option> })}
</datalist>
</div>
)
}
multiFileWidget = (props) => {
return (
<div>
<OverlayTrigger trigger={['hover', 'focus']} placement="right" overlay={fileWidgetPopup}>
<input type="file" id="multiFileName" required={props.required} onChange={(event) => { props.onChange(event.target.value); this.getFileNames(); this.hideResultTables(event.target.id) }} multiple />
</OverlayTrigger>
<textarea id="multiFileNameList" className="form-control" rows="4" style={{ marginTop: "2%" }} readOnly />
</div>
)
}
dropdownTooltipWidget = (props, type, id, tooltip) => {
return (
<div>
<OverlayTrigger trigger={['hover', 'focus']} placement="right" overlay={tooltip} hidden>
<input id={id} type="text" className="form-control" list={type} placeholder="Select one..." onChange={(event) => { props.onChange(event.target.value); this.hideResultTables(event.target.id) }} />
</OverlayTrigger>
<datalist id={type}>
{this.props.actionsObj.filterJsonData(type, this.props.convertDropDownDataObj).map((value, index) => { return <option key={index} value={value}>{value}</option> })}
</datalist>
</div>
)
}
They are stuffed in a object like so:
multiUISchema = {
file: {
'ui:widget': this.multiFileWidget,
classNames: "uiSchema",
},
convertTo: {
'ui:widget': (props) => this.dropdownWidget(props, "ConvertToTypes", "multiConvertTo"),
classNames: "uiSchema"
},
notification: {
'ui:widget': (props) => this.dropdownTooltipWidget(props, "NotificationType", "notification", websNotificationPopup),
classNames: "uiSchema"
}
}
Where things go bad!! This function is injected in the widgets onChange handler.
hideResultTables(targetId) {
debugger;
//disable Retrieve button
if (targetId === 'multiFileName' || targetId === 'multiConvertTo') {
console.log("BEFORE::", this.state.formData)
selectedFiles = [];
document.getElementById("convertResultTable").setAttribute("hidden", true);
document.getElementById("retrieveResultTable").setAttribute("hidden", true);
this.setState({ disabled: true });
}
//leave Retrieve Button enabled
else if (targetId !== 'appIDs') {
console.log("BEFORE::", this.state.formData)
selectedFiles = [];
document.getElementById("convertResultTable").setAttribute("hidden", true);
document.getElementById("retrieveResultTable").setAttribute("hidden", true);
}
}
Basically if I hit the first if statement which has the setState for disabled to True, my onChange doesn't seem to retain the selected dropdown data to the Form Data object. It's like setState for Disabled true, which is for a button unrelated to the field does something to in the reconciliation tree possibly and/or my form data never retains the selected field in the formdata object at all?? idk. The field just stays undefined in all console logs if it's a field that hits that first if statement with the setState in it. But that setState has nothing to do with the fields being selected. It's disabling a button further down the page is all. Im sure im missing some React lifecycle, reconciliation async something or other. Im thinking of just reduxing this all but this simple bool value seems like it should stay as local state to the component. Any thoughts on things I should be checking before i redux this simple bool for my form?
To Further clarify my question, why does setState in the injected function in onChange seem to disrupt the onChange value update for the field on the form in my Widget when I select a field. That's really what this is all about. We cannot figure out why this is happening.
footnote** The dropdown data in the form is redux store data. So im selecting store data in my onchange in the widgets. Not sure if that's relevant.

I can't edit Text Field in Material-UI

I developed a React App using Material-UI then I tried to create independent Components,
check the below independent components(<PanelDiv/>),
render() {
return (
<div className="panelDiv-component" style={{display:this.props.display}}>
<div className="panel-field-content">
<TextField
floatingLabelText={this.props.heading}
type={this.props.inputType}
value={this.props.value}
/>
{/* <input defaultValue className="form-control"></input>*/}
</div>
</div>
);
}
I tried to use the component like this,
<PanelDiv
heading='name'
inputType="text"
value={this.state.userData.name}
display={this.state.display[0]}
/>
But I can't update input field in this way.Also there is no error. How can i solve this? I want to update my input field.
Please check my input filed in the below image :
Because you are controlling the value of TextField by using value attribute but you are not updating the value by using onChange function, Since value of TextField is not changing so it becomes read only.
Solution:
Specify the onChange function with TextField and update the value inside that, Like this:
<TextField
floatingLabelText={this.props.heading}
type={this.props.inputType}
value={this.props.value}
onChange={this.props._change}
/>
Inside parent component:
_Change(event, value){
//update the value here
}
<PanelDiv
heading='name'
inputType="text"
value={this.state.userData.name}
_change={this._change}
display={this.state.display[0]}
/>
If you pass value as a prop to TextField you can't change that text!
On Material-UI official documentation they have used defaultValue="default val" as a prop.
So I used defaultValue as a prop! It worked fine for me!
<TextField
type="text"
defaultValue={this.props.val}
onChange={handleChange}
/>
Had the same error. I was not able to key in anything and it was because there was no name props included. example:
<TextField
type="email"
name='email'/>
Look at this example - https://jsfiddle.net/y857yeLq/
You should define a function, which is handles of text change and pass it to onChange property. In this example I used state for storing current text field value. I see, that you use props for that, but the principle is the same - function should update props in your case.
const { TextField, MuiThemeProvider, getMuiTheme } = MaterialUI;
class SliderExampleControlled extends React.Component {
state = {
value: '',
}
render() {
console.log(this.state);
return (
<div style={{width: '50%', margin: '0 auto'}}>
<TextField
hintText="Type here"
value={this.state.value}
onChange={(e) => this.setState(e.target.value)}
/>
</div>
);
}
}
const App = () => (
<MuiThemeProvider muiTheme={getMuiTheme()}>
<SliderExampleControlled />
</MuiThemeProvider>
);
ReactDOM.render(
<App />,
document.getElementById('container')
);
I was running into this problem as well and I needed the onClick function to take more than just the event I also needed it to take the row number because my state had an array representing the rows in a table. I was able to do that using this chunk of code
onChange={(e) => this.nameChange(e.target.value, row.row_num)}
then in my function called nameChange I was able to update the value

Categories