prometheusresearch-archive / react-forms

Forms library for React.
1.16k stars 113 forks source link

Reset a Form with custom Form Fields #157

Open digitalkaoz opened 7 years ago

digitalkaoz commented 7 years ago

How can i achieve a form reset?

do i need refs on all of my fields?

i can set a new formValue on the root of the form-tree, but the form fields dont reset their values

ifunk commented 7 years ago

Setting a new formValue should reset the form. Can you show your code?

digitalkaoz commented 7 years ago

yes. here the relevant part

import React from 'react'
import TimeField from '../TimeField/TimeField';

const SCHEMA = {
    type: 'object',
    required: [
        'start',
        'end'
    ],
    properties: {
        start: {type: 'string', pattern: /^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/},
        end: {type: 'string', pattern: /^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/},
        break: {type: "string", pattern: /^$|(^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9])$/}
    }
};

class Form extends React.Component {

    constructor(props) {
        super(props);

        let formValue = createValue({
            value: props.value,
            onChange: this.onChange.bind(this),
            schema: SCHEMA
        });

        this.state = {formValue}
    }

    onChange(formValue) {
        this.setState({formValue})
    }

    onReset() {
        let formValue = createValue({
            value: {},
            onChange: this.onChange.bind(this),
            schema: SCHEMA
        });

        this.setState({formValue});
    }

    render() {
        return (
            <Fieldset formValue={this.state.formValue}>
                    <TimeField select="start" label="Start Time"  />
                    <TimeField select="break" label="Break" />
                    <TimeField select="end" label="End Time"  />
                    <button onClick={this.onReset.bind(this)}>reset</button>
            </Fieldset>
        )
    }
}

export Form
import React from 'react'
import {withFormValue, ErrorList} from 'react-forms'

class Field extends React.Component {

    constructor(props) {
        super(props);
        let {formValue} = this.props;
    }

    render() {
        return (
            <div>
                <input type="text" id={this.props.select} value={this.props.formValue.value} onChange={this.onChange.bind(this)} placeholder="HH:mm"/>
                <label >{this.props.label}</label>
                <ErrorList formValue={this.state.value} />
            </div>
        )
    }

    onChange = (e) => this.props.formValue.update(e.target.value)
}

export default withFormValue(Field);
digitalkaoz commented 7 years ago

it resets the form somehow, but the input fields still display values. tried it with default fields and my custom one

ifunk commented 7 years ago

At first glance you need to change this.props.onReset to just this.onReset

On 07/03/2017 8:32 AM, "Robert Schönthal" notifications@github.com wrote:

yes. here the relevant part

import React from 'react'import TimeField from '../TimeField/TimeField'; const SCHEMA = { type: 'object', required: [ 'start', 'end' ], properties: { start: {type: 'string', pattern: /^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/}, end: {type: 'string', pattern: /^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/}, break: {type: "string", pattern: /^$|(^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9])$/} } }; class Form extends React.Component {

constructor(props) {
    super(props);

    let formValue = createValue({            value: props.value,            onChange: this.onChange.bind(this),            schema: SCHEMA
    });
    this.state = {formValue}
}

onChange(formValue) {        this.setState({formValue})
}

onReset() {
    let formValue = createValue({            value: {},            onChange: this.onChange.bind(this),            schema: SCHEMA
    });
    this.setState({formValue});
}

render() {        return (
        <Fieldset formValue={this.state.formValue}>
                <TimeField select="start" label="Start Time"  />
                <TimeField select="break" label="Break" />
                <TimeField select="end" label="End Time"  />
                <button onClick={this.props.onReset.bind(this)}>reset</button>
        </Fieldset>
    )
}

} export Form

import React from 'react'import {withFormValue, ErrorList} from 'react-forms' class Field extends React.Component {

constructor(props) {
    super(props);
    let {formValue} = this.props;
}

render() {        return (
        <div>
            <input type="text" id={this.props.select} value={this.props.formValue.value} onChange={this.onChange.bind(this)} placeholder="HH:mm"/>
            <label >{this.props.label}</label>
            <ErrorList formValue={this.state.value} />
        </div>
    )
}

onChange = (e) => this.props.formValue.update(e.target.value)

} export default withFormValue(Field);

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/prometheusresearch/react-forms/issues/157#issuecomment-284556069, or mute the thread https://github.com/notifications/unsubscribe-auth/AAB4wQ5EZmF2ky0-dhFg6LpN6egI1Bfeks5rjImYgaJpZM4MTZ7x .

ifunk commented 7 years ago

I had a look in more detail and looks like there is a bug with the Input component and its debounce behavior combined with setting form values as undefined. I've never tried to reset a form before so I've never run into this issue.

A simple workaround is to reset the fields as you expect with empty values:

let formValue = createValue({
  value: {
    start: null,
    end: null,
    break: null,
  },
  onChange: this.onChange.bind(this),
  schema: SCHEMA
});
digitalkaoz commented 7 years ago

@ifunk this doesnt change it correctly. the app is hosted here: time-calc.digitalkaoz.net and the source is here https://github.com/digitalkaoz/time-calc

or you can run it with docker: docker run --rm -p 3001:3001 digitalkaoz/time-calc.digitalkaoz.net

as i said the form seems somehow resetted, but the values are still displayed...

ifunk commented 7 years ago

You must set values to null instead of undefined in your reducer.

        case RESET_CALCULATION:
            return Object.assign({}, state, {
                current: {
                    start: null,
                    end: null,
                    duration: null,
                    break: null
                }
            });
digitalkaoz commented 7 years ago

mh yes that works, but then i get a pattern mismatch error as

''.match(/^$|(^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9])$/) fails.

setting the values to undefined the error is correctly required but the displayed value is not removed.

so both options halfway correctly :)

adamroyle commented 7 years ago

Ahh ok. I don't use schema validation so I'm not sure I can help you there. You can apply your own validation using the externalErrorList param on createValue which is what I use when applying server-side and client-side validation.