andyhu92 / react-bootstrap4-form-validation

Simple React Components for form validation. Based on HTML5 Constraint validation API and Bootstrap4 style.
https://andyhu92.github.io/react-bootstrap4-form-validation/
MIT License
15 stars 4 forks source link

How works form submitting? #4

Closed abakumov-v closed 6 years ago

abakumov-v commented 6 years ago

Hi!

I have parent component IncomeOperationItem:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux'
import { Row, Col, Form, FormGroup, Label, Input, FormText, Button, Card, CardBody } from 'reactstrap'
import { ValidationForm, TextInput, SelectGroup, Checkbox, Radio } from 'react-bootstrap4-form-validation'

import AddCopyOperationButton from 'components/Operations/OperationActions/AddCopyOperationButton';
import RemoveOperationButton from 'components/Operations/OperationActions/RemoveOperationButton';
import RemoveSelectedOperation from 'components/Operations/NewOperations/RemoveSelectedOperation';
import { IncomeOperationPropTypes } from 'constants/propTypes/operations';
import {
    changeIncomeOperationAmount, changeIncomeOperationPurse, changeIncomeOperationIncomeItem, changeIncomeOperationTags
} from 'actions/operations';
import {
    createNewTag
} from 'actions/handbooks';
import { PursePropTypes, IncomeItemPropTypes, TagPropTypes } from 'constants/propTypes/handbooks';
import TagsAutocompleteInput from 'components/Operations/NewOperations/base/TagsAutocompleteInput';
import * as arrayUtils from 'utils/arrayUtils';
import IncomeItemsSelector from 'components/Operations/NewOperations/base/IncomeItemsSelector';
import PursesSelector from 'components/Operations/NewOperations/base/PursesSelector';
import OperationAmountInput from 'components/Operations/NewOperations/base/OperationAmountInput';
import OperationTagsInput from 'components/Operations/NewOperations/base/OperationTagsInput';
import { findNewTags } from 'utils/tagsUtils';

class IncomeOperationItem extends Component {
    constructor(props) {
        super(props);
    }

    addCopyOfBlock = () => {
        const { incomeOperation, addCopyOfBlock } = this.props
        addCopyOfBlock(incomeOperation.number)
    }
    removeBlock = (number) => {
        const { removeBlock } = this.props
        removeBlock(number)
    }

    handleChangeAmount = (newAmount) => {
        const { changeIncomeOperationAmount, incomeOperation } = this.props
        changeIncomeOperationAmount(incomeOperation.number, newAmount)
    }
    handleChangeSelectedPurse = (selectedPurse) => {
        const { changeIncomeOperationPurse, incomeOperation } = this.props
        changeIncomeOperationPurse(incomeOperation.number, selectedPurse)
    }
    handleChangeSelectedIncomeItem = (selectedIncomeItem) => {
        const { changeIncomeOperationIncomeItem, incomeOperation } = this.props
        changeIncomeOperationIncomeItem(incomeOperation.number, selectedIncomeItem)
    }
    handleChangeSelectedTags = (selectedTags) => {
        const { tags, changeIncomeOperationTags, incomeOperation } = this.props
        changeIncomeOperationTags(incomeOperation.number, selectedTags)
        if (selectedTags) {
            findNewTags(selectedTags, tags, this.handleCreateNewTag)
        }
    }
    handleCreateNewTag = (newTags) => {
        console.log('New tags: ', newTags)
        const { createNewTag } = this.props

        if (newTags) {
            createNewTag(newTags)
        }
    }
    handleSubmitForm = (e, formData, inputs) => {
        e.preventDefault()

        console.log(e, formData, inputs)
    }
    handleErrors = (e, formData, errorInputs) => {
        console.log('handleErrors: ', e, formData, errorInputs)
    }

    render() {
        const { incomeOperation, isRemoveButtonEnabled, tags, incomeItems, purses } = this.props

        const removeButton = isRemoveButtonEnabled
            ? <RemoveSelectedOperation number={incomeOperation.number} onRemove={this.removeBlock} />
            : null

        const elementIdSuffix = incomeOperation.number
        const purseSelectId = `purseSelect${elementIdSuffix}`
        const plusInputId = `plus${elementIdSuffix}`
        const incomeItemSelectId = `incomeItemSelect${elementIdSuffix}`
        const tagsInputId = `tags${elementIdSuffix}`

        const isHighlightedForRemoveClass = incomeOperation.isHighlightedForRemove
            ? 'operation-details-item--for-remove'
            : ''

        return (
            <li className={`list-group-item list-group-item-light operation-details-item ${isHighlightedForRemoveClass}`}>
                <ValidationForm onSubmit={this.handleSubmitForm}
                    onErrorSubmit={this.handleErrors}
                    immediate={true}
                    setFocusOnError={true}
                >
                    <FormGroup row>
                        <Col sm={5}>
                            <PursesSelector id={purseSelectId}
                                selectedPurse={incomeOperation.purse}
                                purses={purses}
                                onChange={this.handleChangeSelectedPurse} />
                        </Col>
                        <Col sm={6}>
                            <Label for={plusInputId} hidden>Укажите сумму операции</Label>
                            <OperationAmountInput id={plusInputId}
                                selectedValue={incomeOperation.plus}
                                onChange={this.handleChangeAmount}
                            />
                        </Col>
                        <Col sm={1} className='text-right'>
                            <AddCopyOperationButton number={incomeOperation.number} onClick={this.addCopyOfBlock} />
                        </Col>
                    </FormGroup>
                    <FormGroup row>
                        <Col sm={5}>
                            <IncomeItemsSelector id={incomeItemSelectId}
                                selectedIncomeItem={incomeOperation.incomeItem}
                                incomeItems={incomeItems}
                                onChange={this.handleChangeSelectedIncomeItem}
                            />
                        </Col>
                        <Col sm={6}>
                            <OperationTagsInput id={tagsInputId}
                                selectedTags={incomeOperation.tags}
                                tags={tags}
                                onChange={this.handleChangeSelectedTags}
                                onCreateNewTag={this.handleCreateNewTag}
                            />
                        </Col>
                        <Col sm={1} className='text-right'>
                            {removeButton}
                            {/* <button className="btn btn-primary">Submit</button> */}
                        </Col>
                    </FormGroup>
                </ValidationForm>
            </li>
        );
    }
}

IncomeOperationItem.propTypes = {
    incomeOperation: IncomeOperationPropTypes,
    isRemoveButtonEnabled: PropTypes.bool,
    tags: PropTypes.arrayOf(TagPropTypes),
    purses: PropTypes.arrayOf(PursePropTypes),
    incomeItems: PropTypes.arrayOf(IncomeItemPropTypes),

    addCopyOfBlock: PropTypes.func,
    removeBlock: PropTypes.func,
};

export default connect(
    null,
    {
        changeIncomeOperationAmount, changeIncomeOperationPurse, changeIncomeOperationIncomeItem, changeIncomeOperationTags,
        createNewTag
    }
)(IncomeOperationItem);

It looks like this: image I'm not understand how can I submit form inside my block? On each block I have 2 buttons:

When I click on my any button ValidationForm does not throw handleSubmit event. But if I add instead of my "remove button" this code:

<button className="btn btn-primary">Submit</button>

and it's looks like this: image

the ValidationForm raise handleSubmit event! How? :)

andyhu92 commented 6 years ago

According to MDN, the default type attribute of button is submit, so that's why if you use <button className="btn btn-primary">Submit</button>, it will raise the submit event and trigger the handleSubmit. So I assume your other buttons are all have type='button', because you don't want to submit the form when your user click add copy or remove current block button or add new empty block button right? Hope this will explain the issue :)

abakumov-v commented 6 years ago

@andyhu92 thanks for your explanation! I didn't really know that the default value of button type attribute is submit.