Skip to content

Commit

Permalink
WIP that doesnt compile :)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsomsanith-tlnd committed May 15, 2017
1 parent 7ec9032 commit 309dc26
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 27 deletions.
34 changes: 13 additions & 21 deletions packages/forms/src/UIForm/UIForm.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const TRIGGER_AFTER = 'after';
class UIForm extends React.Component {
constructor(props) {
super(props);
const { jsonSchema, uiSchema, properties } = props.data;
const { jsonSchema, uiSchema, properties } = props;
this.state = {
mergedSchema: merge(jsonSchema, uiSchema),
properties: { ...properties },
Expand All @@ -29,13 +29,12 @@ class UIForm extends React.Component {
* @param uiSchema
* @param properties
*/
componentWillReceiveProps({ jsonSchema, uiSchema, properties }) {
if (!jsonSchema || !uiSchema || !properties) {
componentWillReceiveProps({ jsonSchema, uiSchema }) {
if (!jsonSchema || !uiSchema) {
return;
}
this.setState({
mergedSchema: merge(jsonSchema, uiSchema),
properties: { ...properties },
});
}

Expand Down Expand Up @@ -119,9 +118,7 @@ class UIForm extends React.Component {
}

render() {
const { formName } = this.props;
const { properties, validations } = this.state;

const { errors, formName, properties } = this.props;
return (
<form onSubmit={this.submit}>
{
Expand All @@ -132,7 +129,7 @@ class UIForm extends React.Component {
onChange={this.consolidate}
schema={nextSchema}
properties={properties}
validations={validations}
errors={errors}
/>
))
}
Expand All @@ -144,17 +141,12 @@ class UIForm extends React.Component {

if (process.env.NODE_ENV !== 'production') {
UIForm.propTypes = {
/** Form schema configuration */
data: PropTypes.shape({
/** Json schema that specify the data model */
jsonSchema: PropTypes.object,
/** UI schema that specify how to render the fields */
uiSchema: PropTypes.array,
/** Form fields values. Note that it should contains @definitionName for triggers. */
properties: PropTypes.object,
}),
/** The forms errors { [fieldKey]: errorMessage } */
errors: PropTypes.object, // eslint-disable-line react/forbid-prop-types
/** The form name that will be used to create ids */
formName: PropTypes.string,
/** Json schema that specify the data model */
jsonSchema: PropTypes.object, // eslint-disable-line react/forbid-prop-types
/** The change callback. It takes */
onChange: PropTypes.func,
/** Form submit callback */
Expand All @@ -165,6 +157,10 @@ if (process.env.NODE_ENV !== 'production') {
* This is executed on changes on fields with uiSchema > triggers : ['after']
*/
onTrigger: PropTypes.func,
/** Form fields values. Note that it should contains @definitionName for triggers. */
properties: PropTypes.object, // eslint-disable-line react/forbid-prop-types
/** UI schema that specify how to render the fields */
uiSchema: PropTypes.array, // eslint-disable-line react/forbid-prop-types
/**
* Custom validation function.
* Prototype: function validation(properties, fieldName, value)
Expand All @@ -174,7 +170,3 @@ if (process.env.NODE_ENV !== 'production') {
validation: PropTypes.func,
};
}

export default reduxForm({
form: 'form', // a unique name for this form
})(UIForm);
180 changes: 180 additions & 0 deletions packages/forms/src/UIForm/UIForm.container.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import React, { PropTypes } from 'react';
import { reduxForm } from 'redux-form';
import { merge } from 'talend-json-schema-form-core';

import Widget from './Widget';
import { validate, validateAll } from './utils/validation';
import { mutateValue } from './utils/properties';

const TRIGGER_AFTER = 'after';

class UIForm extends React.Component {
constructor(props) {
super(props);
const { jsonSchema, uiSchema, properties } = props.data;
this.state = {
mergedSchema: merge(jsonSchema, uiSchema),
properties: { ...properties },
validations: {},
};
console.log(this.state.mergedSchema)

this.consolidate = this.consolidate.bind(this);
this.submit = this.submit.bind(this);
}

/**
* Update the state with the new schema.
* @param jsonSchema
* @param uiSchema
* @param properties
*/
componentWillReceiveProps({ jsonSchema, uiSchema, properties }) {
if (!jsonSchema || !uiSchema || !properties) {
return;
}
this.setState({
mergedSchema: merge(jsonSchema, uiSchema),
properties: { ...properties },
});
}

/**
* Consolidate form with the new value.
* - it updates the validation on the modified field.
* - it triggers onChange / onTrigger callbacks
* @param event The change event
* @param schema The schema of the changed field
* @param value The new field value
*/
consolidate(event, schema, value) {
this.setState(
(prevState) => {
const properties = mutateValue(prevState.properties, schema.key, value);
const validations = {
...prevState.validations,
[schema.key]: validate(schema, value, properties, this.props.validation),
};
return { properties, validations };
},
() => this.handleChangesCallbacks(schema, value)
);
}

/**
* Triggers the onTrigger and onChange if needed
* - onChange : at each field change
* - onTrigger : when schema.trigger : ['after']
* @param schema The field schema
* @param value The new value
*/
handleChangesCallbacks(schema, value) {
const { onChange, onTrigger } = this.props;

if (onChange) {
onChange({
jsonSchema: this.props.data.jsonSchema, // original jsonSchema
uiSchema: this.props.data.uiSchema, // original uiSchema
properties: this.state.properties, // current properties values
});
}

const { key, triggers } = schema;
if (onTrigger && triggers && triggers.indexOf(TRIGGER_AFTER) !== -1) {
onTrigger(
this.state.properties, // current properties values
key[key.length - 1], // field name
value // field value
);
}
}

/**
* Triggers a validation and update state.
* @returns {boolean} true if the form is valid, false otherwise
*/
isValid() {
const validations = validateAll(
this.state.mergedSchema,
this.state.properties,
this.props.validation
);

const isValid = Object.keys(validations).every(key => validations[key].valid);
if (!isValid) {
this.setState({ validations });
}
return isValid;
}

/**
* Triggers submit callback if form is valid
* @param event the submit event
*/
submit(event) {
event.preventDefault();
if (this.isValid()) {
this.props.onSubmit(event, this.state.properties);
}
}

render() {
const { formName } = this.props;
const { properties, validations } = this.state;

return (
<form onSubmit={this.submit}>
{
this.state.mergedSchema.map((nextSchema, index) => (
<Widget
key={index}
formName={formName}
onChange={this.consolidate}
schema={nextSchema}
properties={properties}
validations={validations}
/>
))
}
<button type="submit" className="btn btn-primary">Submit</button>
</form>
);
}
}

if (process.env.NODE_ENV !== 'production') {
UIForm.propTypes = {
/** Form schema configuration */
data: PropTypes.shape({
/** Json schema that specify the data model */
jsonSchema: PropTypes.object,
/** UI schema that specify how to render the fields */
uiSchema: PropTypes.array,
/** Form fields values. Note that it should contains @definitionName for triggers. */
properties: PropTypes.object,
}),
/** The form name that will be used to create ids */
formName: PropTypes.string,
/** The change callback. It takes */
onChange: PropTypes.func,
/** Form submit callback */
onSubmit: PropTypes.func.isRequired,
/**
* Tigger > after callback.
* Prototype: function onTrigger(properties, fieldName, value)
* This is executed on changes on fields with uiSchema > triggers : ['after']
*/
onTrigger: PropTypes.func,
/**
* Custom validation function.
* Prototype: function validation(properties, fieldName, value)
* Return format : { valid: true|false, error: { message: 'my validation message' } }
* This is triggered on fields that has their uiSchema > customValidation : true
*/
validation: PropTypes.func,
};
}

export default reduxForm({
form: 'form', // a unique name for this form
})(UIForm);
12 changes: 6 additions & 6 deletions packages/forms/src/UIForm/Widget/Widget.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { sfPath } from 'talend-json-schema-form-core';
import widgets from '../utils/widgets';
import { getValue } from '../utils/properties';

export default function Widget({ formName, onChange, properties, schema, validations }) {
export default function Widget({ errors, formName, onChange, properties, schema }) {
const { key, type, validationMessage } = schema;
const id = sfPath.name(key, '-', formName);
const { error, valid } = validations[key] || {};
const errorMessage = validationMessage || (error && error.message);
const error = errors[key];
const errorMessage = validationMessage || error;
const WidgetImpl = widgets[type];
return WidgetImpl ?
(
Expand All @@ -17,18 +17,19 @@ export default function Widget({ formName, onChange, properties, schema, validat
key={id}
errorMessage={errorMessage}
formName={formName}
isValid={valid}
isValid={!error}
onChange={onChange}
properties={properties}
schema={schema}
validations={validations}
errors={errors}
value={getValue(properties, key)}
/>
) : null;
}

if (process.env.NODE_ENV !== 'production') {
Widget.propTypes = {
errors: PropTypes.object, // eslint-disable-line react/forbid-prop-types
formName: PropTypes.string,
onChange: PropTypes.func,
schema: PropTypes.shape({
Expand All @@ -37,6 +38,5 @@ if (process.env.NODE_ENV !== 'production') {
validationMessage: PropTypes.string,
}).isRequired,
properties: PropTypes.object, // eslint-disable-line react/forbid-prop-types
validations: PropTypes.object, // eslint-disable-line react/forbid-prop-types
};
}

0 comments on commit 309dc26

Please sign in to comment.