Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0be655f
added onBlur event
eeinowski Dec 16, 2016
a08b95f
added on blur event
eeinowski Dec 16, 2016
aad1536
removed debugger expression
eeinowski Dec 30, 2016
409341b
removed list from gitignore and built a dist for use with npm
eeinowski Jan 3, 2017
d1fc419
added lib to git repo
eeinowski Jan 3, 2017
353a64f
fixed error in onblur testing
megantfanning Jan 5, 2017
1719a4e
added onBlur check for arrayField_test
megantfanning Jan 11, 2017
7a53913
added onblur test for boolean field
megantfanning Jan 13, 2017
a8a0495
added onBlur for numberfield
megantfanning Jan 13, 2017
b1df603
onBlur testing added for array,number,object,string fields adn uischema
megantfanning Jan 13, 2017
73567cc
added if statement to onblur to ensure it's only called if there is a…
megantfanning Jan 14, 2017
aa7c3cd
fixed arrayfield test
megantfanning Jan 14, 2017
b6334be
Merge pull request #1 from eeinowski/megansOnBlurEvent
megantfanning Jan 16, 2017
8f8936a
addded if block around onBlur event in checkBox widget
megantfanning Jan 16, 2017
30b148d
added on blur test for datetimefield
megantfanning Jan 16, 2017
bea4062
changed expect to match chai styling
megantfanning Jan 16, 2017
d469072
fixed spy syntax
megantfanning Jan 17, 2017
c75af52
fixed error in date time widget test
megantfanning Jan 17, 2017
10c5830
added onblur testing for widgets in stringfield test
megantfanning Jan 17, 2017
f66aa11
added password and textArea widget testing to string tests for onBlur
megantfanning Jan 17, 2017
827d6f1
added widget testing for radio, range, select in numberfield test
megantfanning Jan 18, 2017
4266379
linting project complete
megantfanning Jan 18, 2017
4e01bd6
added information about onBlur to Readme
megantfanning Jan 18, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
npm-debug.log
node_modules
build
dist
lib

.idea
Copy link
Copy Markdown
Collaborator

@n1k0 n1k0 Jan 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be added by IntelliJ users in their own global ~/.gitignore file. Also please readd ignore rules for dist and lib (see contextual comments above).

6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ A [live playground](https://mozilla-services.github.io/react-jsonschema-form/) i
- [Form submission](#form-submission)
- [Form error event handler](#form-error-event-handler)
- [Form data changes](#form-data-changes)
- [Form field blur events](#form-field-blur-events)
- [Form customization](#form-customization)
- [The uiSchema object](#the-uischema-object)
- [Alternative widgets](#alternative-widgets)
Expand Down Expand Up @@ -192,8 +193,10 @@ render((

If you plan on being notified everytime the form data are updated, you can pass an `onChange` handler, which will receive the same args as `onSubmit` any time a value is updated in the form.

## Form customization
#### Form field blur events
Sometimes you may want to trigger events or modify external state when a field has been touched, so you can pass an `onBlur` handler, which will receive the field value.

## Form customization
### The `uiSchema` object

JSONSchema is limited for describing how a given data type should be rendered as a form input component, that's why this lib introduces the concept of *UI schema*.
Expand Down Expand Up @@ -747,6 +750,7 @@ The following props are passed to custom widget components:
- `disabled`: `true` if the widget is disabled;
- `readonly`: `true` if the widget is read-only;
- `onChange`: The value change event handler; call it with the new value everytime it changes;
- `onBlur`: The input blur event handler; call it with the the widget value;
- `options`: A map of options passed as a prop to the component (see [Custom widget options](#custom-widget-options)).
- `formContext`: The `formContext` object that you passed to Form.

Expand Down
5 changes: 5 additions & 0 deletions dist/react-jsonschema-form.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/react-jsonschema-form.js.map

Large diffs are not rendered by default.

41 changes: 41 additions & 0 deletions lib/components/ErrorList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"use strict";

Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = ErrorList;

var _react = require("react");

var _react2 = _interopRequireDefault(_react);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function ErrorList(_ref) {
var errors = _ref.errors;

return _react2.default.createElement(
"div",
{ className: "panel panel-danger errors" },
_react2.default.createElement(
"div",
{ className: "panel-heading" },
_react2.default.createElement(
"h3",
{ className: "panel-title" },
"Errors"
)
),
_react2.default.createElement(
"ul",
{ className: "list-group" },
errors.map(function (error, i) {
return _react2.default.createElement(
"li",
{ key: i, className: "list-group-item text-danger" },
error.stack
);
})
)
);
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for lib files, they're generated locally then published to npm, and should therefore not be versioned in this repository.

286 changes: 286 additions & 0 deletions lib/components/Form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _ErrorList = require('./ErrorList');

var _ErrorList2 = _interopRequireDefault(_ErrorList);

var _utils = require('../utils');

var _validate = require('../validate');

var _validate2 = _interopRequireDefault(_validate);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var Form = function (_Component) {
_inherits(Form, _Component);

function Form(props) {
_classCallCheck(this, Form);

var _this = _possibleConstructorReturn(this, (Form.__proto__ || Object.getPrototypeOf(Form)).call(this, props));

_this.onChange = function (formData) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { validate: false };

var mustValidate = !_this.props.noValidate && (_this.props.liveValidate || options.validate);
var state = { status: "editing", formData: formData };
if (mustValidate) {
var _this$validate = _this.validate(formData),
errors = _this$validate.errors,
errorSchema = _this$validate.errorSchema;

state = _extends({}, state, { errors: errors, errorSchema: errorSchema });
}
(0, _utils.setState)(_this, state, function () {
if (_this.props.onChange) {
_this.props.onChange(_this.state);
}
});
};

_this.onBlur = function () {
if (_this.props.onBlur) {
_this.props.onBlur(_this.state);
}
};

_this.onSubmit = function (event) {
event.preventDefault();
_this.setState({ status: "submitted" });

if (!_this.props.noValidate) {
var _ret = function () {
var _this$validate2 = _this.validate(_this.state.formData),
errors = _this$validate2.errors,
errorSchema = _this$validate2.errorSchema;

if (Object.keys(errors).length > 0) {
(0, _utils.setState)(_this, { errors: errors, errorSchema: errorSchema }, function () {
if (_this.props.onError) {
_this.props.onError(errors);
} else {
console.error("Form validation failed", errors);
}
});
return {
v: void 0
};
}
}();

if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
}

if (_this.props.onSubmit) {
_this.props.onSubmit(_this.state);
}
_this.setState({ status: "initial", errors: [], errorSchema: {} });
};

_this.state = _this.getStateFromProps(props);
return _this;
}

_createClass(Form, [{
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
this.setState(this.getStateFromProps(nextProps));
}
}, {
key: 'getStateFromProps',
value: function getStateFromProps(props) {
var state = this.state || {};
var schema = "schema" in props ? props.schema : this.props.schema;
var uiSchema = "uiSchema" in props ? props.uiSchema : this.props.uiSchema;
var edit = typeof props.formData !== "undefined";
var liveValidate = props.liveValidate || this.props.liveValidate;
var mustValidate = edit && !props.noValidate && liveValidate;
var definitions = schema.definitions;

var formData = (0, _utils.getDefaultFormState)(schema, props.formData, definitions);

var _ref = mustValidate ? this.validate(formData, schema) : {
errors: state.errors || [],
errorSchema: state.errorSchema || {}
},
errors = _ref.errors,
errorSchema = _ref.errorSchema;

var idSchema = (0, _utils.toIdSchema)(schema, uiSchema["ui:rootFieldId"], definitions);
return {
status: "initial",
schema: schema,
uiSchema: uiSchema,
idSchema: idSchema,
formData: formData,
edit: edit,
errors: errors,
errorSchema: errorSchema
};
}
}, {
key: 'shouldComponentUpdate',
value: function shouldComponentUpdate(nextProps, nextState) {
return (0, _utils.shouldRender)(this, nextProps, nextState);
}
}, {
key: 'validate',
value: function validate(formData, schema) {
var validate = this.props.validate;

return (0, _validate2.default)(formData, schema || this.props.schema, validate);
}
}, {
key: 'renderErrors',
value: function renderErrors() {
var _state = this.state,
status = _state.status,
errors = _state.errors;
var showErrorList = this.props.showErrorList;


if (status !== "editing" && errors.length && showErrorList != false) {
return _react2.default.createElement(_ErrorList2.default, { errors: errors });
}
return null;
}
}, {
key: 'getRegistry',
value: function getRegistry() {
// For BC, accept passed SchemaField and TitleField props and pass them to
// the "fields" registry one.
var _getDefaultRegistry = (0, _utils.getDefaultRegistry)(),
fields = _getDefaultRegistry.fields,
widgets = _getDefaultRegistry.widgets;

return {
fields: _extends({}, fields, this.props.fields),
widgets: _extends({}, widgets, this.props.widgets),
FieldTemplate: this.props.FieldTemplate,
definitions: this.props.schema.definitions || {},
formContext: this.props.formContext || {}
};
}
}, {
key: 'render',
value: function render() {
var _props = this.props,
children = _props.children,
safeRenderCompletion = _props.safeRenderCompletion,
id = _props.id,
className = _props.className,
name = _props.name,
method = _props.method,
target = _props.target,
action = _props.action,
autocomplete = _props.autocomplete,
enctype = _props.enctype,
acceptcharset = _props.acceptcharset,
onBlur = _props.onBlur;
var _state2 = this.state,
schema = _state2.schema,
uiSchema = _state2.uiSchema,
formData = _state2.formData,
errorSchema = _state2.errorSchema,
idSchema = _state2.idSchema;

var registry = this.getRegistry();
var _SchemaField = registry.fields.SchemaField;

return _react2.default.createElement(
'form',
{ className: className ? className : "rjsf",
id: id,
name: name,
method: method,
target: target,
action: action,
autoComplete: autocomplete,
encType: enctype,
acceptCharset: acceptcharset,
onSubmit: this.onSubmit },
this.renderErrors(),
_react2.default.createElement(_SchemaField, {
schema: schema,
uiSchema: uiSchema,
errorSchema: errorSchema,
idSchema: idSchema,
formData: formData,
onChange: this.onChange,
onBlur: onBlur,
registry: registry,
safeRenderCompletion: safeRenderCompletion }),
children ? children : _react2.default.createElement(
'p',
null,
_react2.default.createElement(
'button',
{ type: 'submit', className: 'btn btn-info' },
'Submit'
)
)
);
}
}]);

return Form;
}(_react.Component);

Form.defaultProps = {
uiSchema: {},
noValidate: false,
liveValidate: false,
safeRenderCompletion: false
};
exports.default = Form;


if (process.env.NODE_ENV !== "production") {
Form.propTypes = {
schema: _react.PropTypes.object.isRequired,
uiSchema: _react.PropTypes.object,
formData: _react.PropTypes.any,
widgets: _react.PropTypes.objectOf(_react.PropTypes.oneOfType([_react.PropTypes.func, _react.PropTypes.object])),
fields: _react.PropTypes.objectOf(_react.PropTypes.func),
FieldTemplate: _react.PropTypes.func,
onChange: _react.PropTypes.func,
onBlur: _react.PropTypes.func,
onError: _react.PropTypes.func,
showErrorList: _react.PropTypes.bool,
onSubmit: _react.PropTypes.func,
id: _react.PropTypes.string,
className: _react.PropTypes.string,
name: _react.PropTypes.string,
method: _react.PropTypes.string,
target: _react.PropTypes.string,
action: _react.PropTypes.string,
autocomplete: _react.PropTypes.string,
enctype: _react.PropTypes.string,
acceptcharset: _react.PropTypes.string,
noValidate: _react.PropTypes.bool,
liveValidate: _react.PropTypes.bool,
safeRenderCompletion: _react.PropTypes.bool,
formContext: _react.PropTypes.object
};
}
Loading