I would like to know how one can wire in a clear field via redux when using react.
For instance, I have a form with some sample code.
<Field component={datewidget} id ="date" name="date" type="date" label="date" />
<button type="button"onClick={() => {(clearMyInput());}}>
</button>
The function clearMyInput is dispatched such that:
const mapDispatchToProps = (dispatch) => {
return {
clearMyInput: () => {
return dispatch(clearDate(datedata,value));
}
}
}
My question how can one clear the input field by simply clicking on the button and setting the value of the input to none.
For example in jquery, i can write something like this:
$("#button").click(function () {
$("#date").val("");
});
I would like to know how one can do this using redux forms in react.
In your Field's component, pass attribute value from your store and attach event handler to dispatch change.
<Field
component={datewidget}
id="date"
name="date"
type="date"
label="date"
value={this.props.fieldValue}
onChange={this.props.changeFieldValue}
/>
Then with dispatching clearDate function, you just need to set all form's values to ''. I recommend to look into Redux Form which do this all without boilerplate.
I do want to add as a supplement to the existing answer that there is built-in functionality for clearing a form:
<button type="button" onClick={reset}>
Clear Values
</button>
Notice the {reset} onClick action handler here. This comes out of the box with Redux-Form
import { reset, destroy } from 'redux-form'
//
//..code Block
render() {
const { resetForm, destroyForm } = this.props
return <ComponentName {...{ resetForm, destroyForm }} {...this.props} />
}
}
// #formName: for global use(in case if you render more than one form from this container..)
const mapDispatchToProps = dispatch => ({
resetForm: formName => dispatch(reset(formName)),
destroyForm: formName => dispatch(reset(formName)),
})
and now you call it from the component
const ComponentName = ({ resetForm, destroyForm }, ...props) => {
//..code Block
<button type='submit' onClick={() => resetForm('formName') && destroyForm('formName')} > Clear </button>
}
HAPPY CODING..
Related
My app gets initialized with a json payload of 'original values' for attributes in a task form. There is a shared state between various components through a context manager submissionState that also gets imported to this form component. This shared state is a copy of the original values json but includes any edits made to attributes in the payload. I would like to include individual 'reset' buttons for each input of the form which would update the shared state to the original value in the json payload. The original values get passed into the parent form component as props and the edited value state gets called from within the parent component as well.
const FormInput = ({ fieldName, fieldValue, onChange, originalValue }) => {
const handleReset = e => {
//????
}
return (
<div>
<label htmlFor={fieldName}>
{fieldName}
</label>
<br />
<input type="text"
name={fieldName}
value={fieldValue}
onChange={onChange}/>
<button id="reset" onClick={handleReset}>↻</button>
<br />
<div>{originalValue}</div>
</div>
);
};
const TaskForm = (payload: TaskPayload) => {
const { submissionState, setSubmission } = useTask();
function handleChange(evt) {
const value = evt.target.value;
setSubmission({
...submissionState,
[evt.target.name]: value,
});
}
const taskFields = ["name", "address", "address_extended", "postcode", "locality", "region", "website"];
return (
<div>
<form>
{taskFields.map((field) => {
<FormInput
key={field}
fieldName={field}
fieldValue={submissionState[field]}
onChange={handleChange}
originalValue={payload[field]}
/>
})
}
</form>
</div>
);
};
export default TaskForm;
What I would like to do is include logic in the reset button function so that any edits which were made in a form input (from state) get reverted to the original value (stateless), which comes from the payload props: payload[field].
The form input is controlled through a global shared state submissionState, so the reset button logic can either modify the shared state itself with something like:
const handleReset = (submissionState,setSubmissionState) => {
setSubmission({
...submissionState,
fieldName: originalValue,
});
but I would need to pass the submissionState and setSubmission down through to the child component. It would be better if I can somehow update the value attribute in the input, which in-turn should potentially update the shared state? And the logic can just be something like this (assuming I can somehow access the input's value state in the reset button)
const handleReset = (?) => {
/*psuedo code:
setInputValueState(originalValue)
*/
}
I would highly recommend using react-hook-form if it's an option. I've implemented it across several projects and it has never let me down. If it's just not possible to use a library, then keep in mind that React is usually unidirectional. Don't try to work around it, since it works that way by design for most cases you can encounter. Otherwise…
const TaskForm = (payload: TaskPayload) => {
const { submissionState, setSubmission } = useTask();
const upsertSubmission = (upsert) =>
setSubmission({
...submissionState,
...upsert,
});
const handleChange = ({ target }) => {
upsertSubmission({
[target.name]: target.value,
});
};
const reset =
(originalValue) =>
({ target }) => {
upsertSubmission({
[target.name]: originalValue,
});
};
/* Also something like this. RHF will handle most of this for you!
* const reset = (originalValue, fieldName) =>
* upsertSubmission({[fieldName]: originalValue})
*/
const taskFields = [];
return (
<div>
<form>
{taskFields.map((field) => (
<FormInput
key={field}
fieldName={field}
onChange={handleChange}
reset={reset(originalValue)}
value={submissionState[field]}
/>
))}
</form>
</div>
);
};
How can I setState() another input value with a button in the same component in React?
I'm using the onClick event handler on the button.
I want to make the handleClickfunction which I gave it to the button, to target the value of the input
class Search extends Component {
state = {
searchInput: "",
};
handleClick = () => {
this.setState({
searchInput: input.value,
});
};
render() {
return (
<div>
<input type="text"/>
<button onClick={this.handleClick}>Enter</button>
</div>
);
}
}
Your question is not clear, I believe you are asking how to set the value of an input field when you press a button in react.
If that is correct, then you have done most of the work already, all you need to do now is add an <input> tag.
Like this:
<input type="text" value={ this.state.searchInput } />
If I have misunderstood your question then please clarify.
It may be worth reading about how State and Lifecycle work in React Here
Whenever the setState() function is triggered, React automatically runs the render() function in any components where state has changed, rerendering that component with the new state values.
Edit
After clarification I now understand exactly what you want.
You require the use of a ref, like this:
class Search extends Component {
state = {
searchInput: "",
};
handleClick = () => {
this.setState({
searchInput: this.inputText,
});
};
render() {
return (
<div>
<input type="text" ref={(x) => this.inputText = x}/>
<button onClick={this.handleClick}>Enter</button>
</div>
);
}
}
instead of using a button to update the state try this:
<input type="text" onChange={(e) => this.setState({searchInput: e.target.value }) />
Is there any way of autosubmitting a form as soon as it is created? I have a component <ShowVideo />. Inside this component, I'm dispatching an action which will give some hidden field and signatures. Afterwards, I'm rendering this form on the page. What I want is to submit this form dynamically once my form is rendered. There can be multiple forms.
One approach which came to my mind was to call another function handleSubmit after form tag, which will have form.submit() method inside it but how will I make sure that the entire form is rendered or not.
class ShowVideo extends Component {
render() {
let renderInputFields = null
if (this.props.videoData.data.hasOwnProperty("signature")) {
renderInputFields = Object.keys(launchData).map((key, i) => {
return (<input type="hidden" name={key} key={i} value={launchData[key]} />)
})
}
return (
<div>
<iframe width="100%" height="430px" frameBorder="0" name="videoIframe"></iframe>
<form name="ltiLaunchForm" id="ltiLaunchForm" method="post" target="target_iframe" encType="application/x-www-form-urlencoded" action={launchUrl}>
{renderInputFields}
<input type="hidden" name="oauth_signature" value={signature} />
</form>
</div>
)
}
}
A more contemporary solution (using React Hooks) might look like:
import React, { useEffect, useRef } from "react";
const AutoSubmitForm = ({
actionUrl,
params
}) => {
const formRef = useRef(null);
useEffect(() => {
formRef.current.submit();
}, []);
return (
<form ref={formRef} method="POST" action={actionUrl}>
{Object.keys(params).map(name => (
<input
type="hidden"
name={name}
value={params[name]}
></input>
))}
</form>
);
};
If you want to auto submit the form after it's been created but the form has some of its elements rendered later, then i recommend adding a componentDidUpdate lifecycle function that will dynamically trigger after a new rerender.
In this function we will detect if the rerender has rendered all of the form elements. If so, then we can programmatically trigger the form submit.
componentDidUpdate() {
const formElementKey1Exists = document.getElementById("element1");
const formElementKey2Exists = document.getElementById("element2");
...
if (formElementKey1Exists && formElementKey2Exists && ...) {
document.getElementById('ltiLaunchForm').submit();
}
}
The conditional will ensure your entire form is rendered before dynamically submitting.
I am new to React and learning it on my own, I am trying to implement a simple form where the user can provide a name and it will then be store is the state. Once he stop typing and clink on send the the name is store and the fields is
in the input is reset not the state.
This is what i tried and i get
an error saying that cannot read property "then"
changeFun = (e) => {
this.setState({name: e.target.value})
}
submitFun = (e) => {
e.preventDefault()
this.setState({ name: e.target.value})
}
render() {
return (
<input type = "text" value={this.state.name}/>
<button
onSubmit = {(e) =>
this.submitFun(e).then(
() => reset()
)
onchange ={this.changeFun}}>
SEND
</button>
)
}
submitFun is not returning a promise. So you can't use .then after it.
submitFun = (e) => {
e.preventDefault()
// this.setState({name: e.target.value}) should not be here
// because e.target is <button/>
this.setState({name: ''}) // This will reset the input value
}
<button onClick = {this.submitFun} onchange ={this.changeFun}>SEND</button>
In addition you need to use onClick instead of onSubmit for <button> tag.
onSubmit will be used for <form> tag.
what are you trying to achieve is called Controlled Component! more info here.
the base of Controlled Component is basically you have a property in your state and a form element (i.e and input element). then you chain that input value to your state by a function, and that function is going to run on onChange event, to update the state on every change.
something like this:
class App extends React.Component {
constructor(props) {
super()
this.state = {
inputValue: ""
}
}
handleChange = e => {
const _tempValue = e.target.value
e.preventDefault()
this.setState({inputValue: _tempValue})
}
handleSubmit = e => {
const {inputValue} = this.state
e.preventDefault()
// here is your data
// save it to redux or do what ever you want to
console.log(inputValue)
// last thing here is gonna be to reset state after submition
this.setState({inputValue: ""})
}
render() {
const {inputValue} = this.state
return (
<div>
<form onSubmit={this.handleSubmit}>
<input
value={inputValue}
onChange={this.handleChange}
placeholder="type something"
/>
<input type="submit" />
</form>
<p>{inputValue}</p>
</div>
)
}
}
this is a basic implementation of what you want to do, its here: https://codesandbox.io/s/m39w10olnp
on the example that you provide though , you using then that is basically used when that you returning a promise from a function, something like this:
export const giveMeArray= () => {
return new Promise( (res,rej) => {
setTimeout(() => {
res(Object.assign([], myArray))
}, delay);
})
}
so as you can see there is no need to use then here, check my simple example to implement in a better way!
Redux-form "Field" component provides onChange property. A callback that will be called whenever an onChange event is fired from the underlying input. This callback allows to get "newValue" and "previousValue" for the Field.
React-final-form "Field" component doesn't have this property.
So, how I can get the same functionality?
React-final-form handles this functionality with a tiny external package.
Basically it is an additional component to add inside the form that binds to the element using its name:
<Field name="foo" component="input" type="checkbox" />
<OnChange name="foo">
{(value, previous) => {
// do something
}}
</OnChange>
The current documentation can be found here:
https://github.com/final-form/react-final-form-listeners#onchange
The idea under change detection is to subscribe to value changes of Field and call your custom onChange handler when value actually changes. I prepared simplified example where you can see it in action. Details are in MyField.js file.
As the result you can use it just as with redux-form:
<MyField
component="input"
name="firstName"
onChange={(val, prevVal) => console.log(val, prevVal)}
/>
2022 JANUARY UPDATE
While the code above still works (check the sandbox version) there is a case when the solutions requires more tweeks around it.
Here is an updated sandbox with an implementation via the hooks. It's based on a useFieldValue hook and OnChange component as a consumer of this hook. But the hook itself can be used separately when you need previous value between re-renders. This solution doesn't rely on meta.active of the field.
// useFieldValue.js
import { useEffect, useRef } from "react";
import { useField } from "react-final-form";
const usePrevious = (val) => {
const ref = useRef(val);
useEffect(() => {
ref.current = val;
}, [val]);
return ref.current;
};
const useFieldValue = (name) => {
const {
input: { value }
} = useField(name, { subscription: { value: true } });
const prevValue = usePrevious(value);
return [value, prevValue];
};
export default useFieldValue;
// OnChange.js
import { useEffect } from "react";
import useFieldValue from "./useFieldValue";
export default ({ name, onChange }) => {
const [value, prevValue] = useFieldValue(name);
useEffect(() => {
if (value !== prevValue) {
onChange(value, prevValue);
}
}, [onChange, value, prevValue]);
return null;
};
Another nice option is this answer: https://stackoverflow.com/a/56495998/3647991
I haven't used redux-form, but I added a super simple wrapper around the Field component to listen to onChange like this:
const Input = props => {
const {
name,
validate,
onChange,
...rest
} = props;
return (
<Field name={name} validate={validate}>
{({input, meta}) => {
return (
<input
{...input}
{...rest}
onChange={(e) => {
input.onChange(e); //final-form's onChange
if (onChange) { //props.onChange
onChange(e);
}
}}
/>
)}}
</Field>
);
};
One could use the Field's parse attribute and provide a function that does what you need with the value:
<Field
parse={value => {
// Do what you want with `value`
return value;
}}
// ...
/>
You need to use the ExternalModificationDetector component to listen for changes on the field component like this:
<ExternalModificationDetector name="abc">
{externallyModified => (
<BooleanDecay value={externallyModified} delay={1000}>
{highlight => (
<Field
//field properties here
/>
)}
</BooleanDecay>
)}
</ExternalModificationDetector>
By wrapping a stateful ExternalModificationDetector component in a
Field component, we can listen for changes to a field's value, and by
knowing whether or not the field is active, deduce when a field's
value changes due to external influences.
Via - React-Final-Form Github Docs
Here is a sandbox example provided in the React-Final-Form Docs: https://codesandbox.io/s/3x989zl866