I have a project with react,redox and material-ui. there are some textfields on page and I want to show save button only when at least one of textfields is changed. I could add some function to onChange of textfields and set isDirty to true and show button when this property set to true. but I'm wondering is there any clean and good way to do this?
If you are already using Redux. I am suggesting you to have a look at Redux Form - https://github.com/redux-form/redux-form
In redux form, after you initialize the redux form on your component, you may use Field component for each of your input.
<Field component="input" type="text" />
By using the reduxForm High-order component, it will inject some of the props like dirty,pristine,touch etc.. which helps you to show or hide your button.
export default reduxForm({
form: 'formName' // a unique identifier for this form
})(YourComponent)
Related
I have the following structure in my ReactJS App - CodeSandBox link.
I'm trying to somehow submit the Formik form by using a button of Bootstrap modal window, however I am unable to understand how to call the form submission from 2 components down the tree and bring the functions together.
Could someone kindly advise whether it's even something that can be achieved?
Thanks!
In the FormFields component, you need to add an id to your form
<Form id="fooId">
and for the modal button you add the form and type attribute like:
<Button
...
type="submit"
form="fooId"
...
/>
And the form would be submitted. You can skip passing the onClick event to that button and pass the doSubmit method to the Formik component in FormFields component.
Codesandbox
So, I'm trying to use Semantic UI modal component with the form component.
My problem is that if I use these two together the UI becomes bad.
I created a sandbox about my current situation: https://codesandbox.io/s/2n1pj96ry
As you can see now the submit button does not attached to the form.
If I move the Form component directly inside the Modal component, like this:
<Modal...>
<Form>
...
</Form>
</Modal>
the submit will attached to the form, but the UI breakes down.
I tried to add different classes to these components (like ui modal to the Form component, but it doesnt worked well).
Do you have any suggetsion?
Thanks for you help!
You can use the as prop on the Modal to make it a form element.
<Modal
as={Form}
onSubmit={e => handleSubmit(e)}
open={true}
size="tiny">
Any button with the submit type in your modal will fire the onSubmit handler. I find this to be a nice way to opt-in to required fields and easy validation by the browser on form elements.
Be sure to pass the event to your submit handler and use the preventDefault method to avoid the browser from automatically trying to post your form.
Forked your sandbox and made a working example. The modal is changed to a <form> element, the Input has the required property and the browser will demand the element is valid before firing the onSubmit handler. The default form action is prevented, and you can handle as desired with whatever.
In Vue.js :
By default, v-model syncs the input with the data after each input event (with the exception of IME composition as stated above). You can add the lazy modifier to instead sync after change events:
<!-- synced after "change" instead of "input" -->
<input v-model.lazy="msg" >
Does react has the similar modifier or function?In which part of the official doc?
The following is from Vue docs for v-model:
Although a bit magical, v-model is essentially syntax sugar for
updating data on user input events
In React, you can listen to any input event ( onChange, onClick, etc. ) and trigger a function that updates the React Component's state. If you want to pass the data down, you can pass it as props to any children. In this way we can keep data updated with input events. For more info, see React State and React Component and Props
onChange (in React) will do exactly what v-model do in VueJS.
Vue <input type="text" v-model="record" />
React <input type="text" name="record" onChange={e => setRecord(e.target.value)} />
You can use onBlur event on input field in order to achieve functionality similar to v-model.lazy in VueJS.
Vue <input type="text" v-model.lazy="record" />
React <input type="text" name="record" onBlur={e => setRecord(e.target.value)} />
The .lazy modifier in Vue.js will sync on DOM's change events instead of input. DOM's change events occur in a variety of situations depending on the form element used. A check box or radio button will trigger a change event when it’s clicked. An input text box will trigger a change event when it loses focus. Different browsers might not trigger change events on the same interactions.
However, React's onChange works differently than onChange in the DOM: it’s more like DOM's onInput. React's onChange fires when there is a change in any of the form’s input elements, in contrast to the DOM’s change event.
In React.js, if you'd like to have the similar behaviour as Vue.js' v-model.lazy, you need to bind the event handler to a different event.
In regard to your example, in Vue.js we have:
<!-- synced after "change" instead of "input" -->
<input v-model.lazy="msg" >
In React.js, we cannot use onChange, as the onChange handler is fired on every key stroke, not just when the whole input field has changed. React.js' onChange is not "lazy" :-) Instead, you can use its onBlur event:
class MyComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
msg: ''
}
}
handleBlur(event) {
this.setState({msg: event.target.value});
}
render() {
return <div>
<input type="text" onBlur={this.handleBlur.bind(this)}/>
<p>Your message: {this.state.msg}</p>
</div>
}
});
Here's the example on jsfiddle.
I have two components List and Form. Onthes components, i'm using Dropzone
I disabled click, just Drag and Drop is possible
But, on the form component, I would like to add a button, wich enable to add a dcument in browsing.
In the form component, I call my component dropzone
<UploadZone onupload={this.props.onCreateDocument} onsuccessupload={this.uploadedfile} lastfileupload={this.props.lastuploadfile} />
I've added my button :
<RaisedButton label="Add" primary={true} onClick={this.browseDz}/>
browseDz = () => {
}
I don't know how call Dropzone on the button to add a document
Thank you for yours answers
You wouldn't use Dropzone for this part, you implement it yourself. You could use the trick where you put this button in a <label htmlFor={id}> and have a file input with the same id. You'll have two ways of receiving files, so just store the latest selection from the user in one state key.
given the fact in the example http://redux-form.com/6.0.5/examples/fieldArrays/. All the renderField.. functions are outside of the React Class. Hence how am i suppose to use react state or props to determine whether i want to hide or show a Field?
What I'm trying to do is to have a button to manipulate a state to display 'block' or 'none' for a Field. Can someone guide me? I tried to put the renderField variable inside the render of the React class, however this result in bugs.
All the props which are passed to Field are accessible to component props.
<Field
name={foo}
type="text"
component={TextField}
displayBlock={displayBlock}
/>
const TextField = props => {
if(props.displayBlock) {
...
}
return (
<div>
<input {...props.input} />
</div>
);
};
Thanks to Runaground who suggested an answer to me. I came to realized that I can pass in state as props to the FieldArray, such as
<FieldArray name="histories" component={renderHistories} openClose={this.state.openClose}/>
This allow me to utilize an array of state from this.state.openClose, to control which field i would like to hide or show.
<Field
name={`${histories}.details`}
type="text"
component={renderField}
style={{display: openClose[index] ? 'block' : 'none'}}
/>
However, even though I am able to control the display of the Field, the field array does not get rerendered.
Hence, I have to add on two functions
fields.push({});
setTimeout(()=>{
fields.pop();
}, 1);
that is taken from http://redux-form.com/6.0.5/docs/api/FieldArray.md/, to actually rerender the fieldarray whenever i hide or show the field. Hopefully there is a more elegant way to do this as the fieldarray does flicker.