| /** |
| * ValidationForm should be used in order to have a form that handles it's internal validation state. |
| * All ValidationInputs inside the form are checked for validity and the styling and submit buttons |
| * are updated accordingly. |
| * |
| * The properties that ahould be given to the form: |
| * labledButtons - whether or not use icons only as the form default buttons or use buttons with labels |
| * onSubmit - function for click on the submit button |
| * onReset - function for click on the reset button |
| */ |
| import React from 'react'; |
| import JSONSchema from 'nfvo-utils/json/JSONSchema.js'; |
| import JSONPointer from 'nfvo-utils/json/JSONPointer.js'; |
| import ValidationButtons from './ValidationButtons.jsx'; |
| |
| class ValidationForm extends React.Component { |
| |
| static childContextTypes = { |
| validationParent: React.PropTypes.any, |
| isReadOnlyMode: React.PropTypes.bool, |
| validationSchema: React.PropTypes.instanceOf(JSONSchema), |
| validationData: React.PropTypes.object |
| }; |
| |
| static defaultProps = { |
| hasButtons : true, |
| onSubmit : null, |
| onReset : null, |
| labledButtons: true, |
| onValidChange : null, |
| isValid: true |
| }; |
| |
| static propTypes = { |
| isValid : React.PropTypes.bool, |
| isReadOnlyMode : React.PropTypes.bool, |
| hasButtons : React.PropTypes.bool, |
| onSubmit : React.PropTypes.func, |
| onReset : React.PropTypes.func, |
| labledButtons: React.PropTypes.bool, |
| onValidChange : React.PropTypes.func, |
| onValidityChanged: React.PropTypes.func, |
| schema: React.PropTypes.object, |
| data: React.PropTypes.object |
| }; |
| |
| state = { |
| isValid: this.props.isValid |
| }; |
| |
| constructor(props) { |
| super(props); |
| this.validationComponents = []; |
| } |
| |
| componentWillMount() { |
| let {schema, data} = this.props; |
| if (schema) { |
| this.processSchema(schema, data); |
| } |
| } |
| |
| componentWillReceiveProps(nextProps) { |
| let {schema, data} = this.props; |
| let {schema: nextSchema, data: nextData} = nextProps; |
| |
| if (schema !== nextSchema || data !== nextData) { |
| if (!schema || !nextSchema) { |
| throw new Error('ValidationForm: dynamically adding/removing schema is not supported'); |
| } |
| |
| if (schema !== nextSchema) { |
| this.processSchema(nextSchema, nextData); |
| } else { |
| this.setState({data: nextData}); |
| } |
| } |
| } |
| |
| processSchema(rawSchema, rawData) { |
| let schema = new JSONSchema(); |
| schema.setSchema(rawSchema); |
| let data = schema.processData(rawData); |
| this.setState({ |
| schema, |
| data |
| }); |
| } |
| |
| render() { |
| // eslint-disable-next-line no-unused-vars |
| let {isValid, isReadOnlyMode, hasButtons, onSubmit, labledButtons, onValidChange, onValidityChanged, schema, data, children, ...formProps} = this.props; |
| return ( |
| <form {...formProps} onSubmit={event => this.handleFormSubmit(event)}> |
| <div className='validation-form-content'>{children}</div> |
| {hasButtons && <ValidationButtons labledButtons={labledButtons} ref='buttons' isReadOnlyMode={isReadOnlyMode}/>} |
| </form> |
| ); |
| } |
| |
| handleFormSubmit(event) { |
| event.preventDefault(); |
| let isFormValid = true; |
| this.validationComponents.forEach(validationComponent => { |
| const isInputValid = validationComponent.validate().isValid; |
| isFormValid = isInputValid && isFormValid; |
| }); |
| if(isFormValid && this.props.onSubmit) { |
| return this.props.onSubmit(event); |
| } else if(!isFormValid) { |
| this.setState({isValid: false}); |
| } |
| } |
| |
| componentWillUpdate(nextProps, nextState) { |
| if(this.state.isValid !== nextState.isValid && this.props.onValidityChanged) { |
| this.props.onValidityChanged(nextState.isValid); |
| } |
| } |
| |
| componentDidUpdate(prevProps, prevState) { |
| // only handling this programatically if the validation of the form is done outside of the view |
| // (example with a form that is dependent on the state of other forms) |
| if (prevProps.isValid !== this.props.isValid) { |
| if (this.props.hasButtons) { |
| this.refs.buttons.setState({isValid: this.state.isValid}); |
| } |
| } else if(this.state.isValid !== prevState.isValid) { |
| if (this.props.hasButtons) { |
| this.refs.buttons.setState({isValid: this.state.isValid}); |
| } |
| // callback in case form is part of bigger picture in view |
| if (this.props.onValidChange) { |
| this.props.onValidChange(this.state.isValid); |
| } |
| } |
| } |
| |
| componentDidMount() { |
| if (this.props.hasButtons) { |
| this.refs.buttons.setState({isValid: this.state.isValid}); |
| } |
| } |
| |
| |
| getChildContext() { |
| return { |
| validationParent: this, |
| isReadOnlyMode: this.props.isReadOnlyMode, |
| validationSchema: this.state.schema, |
| validationData: this.state.data |
| }; |
| } |
| |
| |
| /*** |
| * Used by ValidationInput in order to let the (parent) form know |
| * the valid state. If there is a change in the state of the form, |
| * the buttons will be updated. |
| * |
| * @param validationComponent |
| * @param isValid |
| */ |
| childValidStateChanged(validationComponent, isValid) { |
| if (isValid !== this.state.isValid) { |
| let oldState = this.state.isValid; |
| let newState = isValid && this.validationComponents.filter(otherValidationComponent => validationComponent !== otherValidationComponent).every(otherValidationComponent => { |
| return otherValidationComponent.isValid(); |
| }); |
| |
| if (oldState !== newState) { |
| this.setState({isValid: newState}); |
| } |
| } |
| } |
| |
| register(validationComponent) { |
| if (this.state.schema) { |
| // TODO: register |
| } else { |
| this.validationComponents.push(validationComponent); |
| } |
| } |
| |
| unregister(validationComponent) { |
| this.childValidStateChanged(validationComponent, true); |
| this.validationComponents = this.validationComponents.filter(otherValidationComponent => validationComponent !== otherValidationComponent); |
| } |
| |
| onValueChanged(pointer, value, isValid, error) { |
| this.props.onDataChanged({ |
| data: JSONPointer.setValue(this.props.data, pointer, value), |
| isValid, |
| error |
| }); |
| } |
| } |
| |
| |
| export default ValidationForm; |