Skip to content

Commit

Permalink
Merge branch 'master' of github.com:Limenius/liform-react
Browse files Browse the repository at this point in the history
  • Loading branch information
nacmartin committed Sep 8, 2017
2 parents 519450b + 7b015a4 commit 8a18a25
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 35 deletions.
78 changes: 65 additions & 13 deletions src/buildSyncValidation.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,75 @@ import Ajv from 'ajv'


const setError = (errors, error) => {
const dataPathParts = error.dataPath.split('.').slice(1)

dataPathParts.reduce((errors, part, index) => {
if (index === dataPathParts.length -1) {
errors[part] = error.message
}
if (!errors[part]) {
errors[part] = {}
}
return errors[part]
}, errors)
if(error.dataPath.charAt(0) == '.') {
const dataPathParts = error.dataPath.split('.').slice(1)
// regular expression to get the object path and index from the ajv error data path
const re = /(^\w+)\[([0-9]+)\]/gm

dataPathParts.reduce((errors, part, index) => {
let res = re.exec(part)

if(res && res.length>0) {
let p = res[1]
let i = res[2]
if(!errors[p]) {
errors[p] = []
}
if(typeof errors[p]=='string') {
let err = errors[p]
errors[p] = []
errors[p]._error = err
}
if (index === dataPathParts.length -1) {
errors[p][i] = error.message
}else{
errors[p][i] = errors[p][i] || {}
}
return errors[p][i]
}
if (index === dataPathParts.length -1) {
if(typeof errors == 'string') {
let err = errors
errors = []
errors._error = err
errors[part] = error.message
}
else{
errors[part] = error.message
}
}
if (!errors[part]) {
errors[part] = {}
}
return errors[part]
}, errors)
}else{
const dataPathParts = error.dataPath.split('/').slice(1)
dataPathParts.reduce((errors, part, index) => {
if (index === dataPathParts.length -1) {
if(typeof errors == 'string') {
let err = errors
errors = []
errors._error = err
errors[part] = error.message
}
else{
errors[part] = error.message
}

}
if (!errors[part]) {
errors[part] = {}
}
return errors[part]
}, errors)
}
return errors
}


const buildSyncValidation = schema => {
const ajv = new Ajv({ errorDataPath: 'property', allErrors: true })
const buildSyncValidation = (schema,
ajv = new Ajv({ errorDataPath: 'property', allErrors: true }) ) => {
return values => {
let errors = {}
const valid = ajv.validate(schema, values)
Expand Down
3 changes: 2 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const Liform = (props) => {
const formName = props.formKey || props.schema.title || 'form'
const FinalForm = reduxForm({
form: props.formKey || props.schema.title || 'form',
validate: props.syncValidation || buildSyncValidation(schema),
validate: props.syncValidation || buildSyncValidation(schema, props.ajv),
initialValues: props.initialValues,
context: { ...props.context, formName },
})(props.baseForm || BaseForm)
Expand All @@ -44,6 +44,7 @@ Liform.propTypes = {
formKey: PropTypes.string,
baseForm: PropTypes.func,
context: PropTypes.object,
ajv: PropTypes.object,
}

export default Liform
Expand Down
7 changes: 5 additions & 2 deletions src/renderField.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,24 @@ const renderField = (fieldSchema, fieldName, theme, prefix = '', context = {}, r
fieldSchema = { ...fieldSchema, ...deepmerge.all(fieldSchema.allOf) }
delete fieldSchema.allOf
}

const widget = guessWidget(fieldSchema)

if (!theme[widget]) {
throw new Error('liform: ' + widget + ' is not defined in the theme')
}

const newFieldName = prefix ? prefix + fieldName : fieldName

return React.createElement(theme[widget], {
key: fieldName,
fieldName: prefix ? prefix + fieldName : fieldName,
fieldName: widget == 'oneOf'? fieldName: newFieldName,
label: fieldSchema.showLabel === false ? '' : fieldSchema.title || fieldName,
required: required,
schema: fieldSchema,
theme,
context,
prefix
})
}

Expand Down
44 changes: 34 additions & 10 deletions src/themes/bootstrap3/ArrayWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,37 @@ import renderField from '../../renderField'
import { FieldArray } from 'redux-form'
import _ from 'lodash'
import ChoiceWidget from './ChoiceWidget'
import classNames from 'classnames'

const renderArrayFields = (count, schema, theme, fieldName, remove, context) => {
const renderArrayFields = (count, schema, theme, fieldName, remove, context, swap) => {
const prefix = fieldName + '.'
if (count) {
return _.times(count, (idx) => {
return (
<div key={idx}>
<button className="pull-right btn btn-danger" onClick={(e) => {
e.preventDefault()
remove(idx)
}}><span className="glyphicon glyphicon-trash"></span></button>
{renderField({ ...schema, showLabel : false }, idx.toString(), theme, prefix, context)}
</div>
<div key={idx}>
<div className="btn-group pull-right ">

{(idx!=count-1 && count>1)?
<button className="btn btn-primary" onClick={(e)=>{
e.preventDefault()
swap(idx, idx+1)
}}><span className="glyphicon glyphicon-arrow-down"></span></button>:''
}
{(idx!=0 && count>1)?
<button className="btn btn-primary" onClick={(e)=>{
e.preventDefault()
swap(idx, idx-1)
}}><span className="glyphicon glyphicon-arrow-up"></span></button>:''
}

<button className="btn btn-danger" onClick={(e) => {
e.preventDefault()
remove(idx)
}}><span className="glyphicon glyphicon-trash"></span></button>

</div>
{renderField({ ...schema, showLabel : false }, idx.toString(), theme, prefix, context)}
</div>
)
})
} else {
Expand All @@ -25,10 +43,16 @@ const renderArrayFields = (count, schema, theme, fieldName, remove, context) =>
}

const renderInput = field => {
const className = classNames([
'arrayType',
{ 'has-error' : field.meta.touched && field.meta.error }
])

return (
<div className="arrayType form-group">
<div className={className}>
<legend className="control-label" >{field.label}</legend>
{ renderArrayFields(field.fields.length, field.schema.items, field.theme, field.fieldName, (idx) => field.fields.remove(idx), field.context) }
{field.meta.touched && field.meta.error && <span className="help-block">{field.meta.error}</span>}
{ renderArrayFields(field.fields.length, field.schema.items, field.theme, field.fieldName, (idx) => field.fields.remove(idx), field.context, (a, b) => {field.fields.swap(a,b)}) }
<button type="button" className="pull-right btn btn-primary" onClick={() => field.fields.push({})}>Add</button>
<div className="clearfix"/>
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/themes/bootstrap3/MoneyWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ const renderInput = field => {
<div className={className}>
<label className="control-label" htmlFor={'field-'+field.name}>{field.label}</label>
<div className="input-group">
<span className="input-group-addon"></span>
<input {...field.input} type="number" className="form-control" id={'field-'+field.name} required={field.required} placeholder={field.placeholder}/>
<span className="input-group-addon"></span>
<input {...field.input} type="number" className="form-control" id={'field-'+field.name} required={field.required} placeholder={field.placeholder}/>
</div>
{field.meta.touched && field.meta.error && <span className="help-block">{field.meta.error}</span>}
{field.description && <span className="help-block">{field.description}</span>}
Expand Down
6 changes: 3 additions & 3 deletions src/themes/bootstrap3/ObjectWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import renderFields from '../../renderFields'

const Widget = props => {
return (
<div>
{props.label && <legend>{props.label}</legend>}
{renderFields(props.schema, props.theme, props.fieldName && props.fieldName + '.', props.context)}
<div className="objectType">
{props.label && <legend>{props.label}</legend>}
{renderFields(props.schema, props.theme, props.fieldName && props.fieldName + '.', props.context)}
</div>
)
}
Expand Down
4 changes: 2 additions & 2 deletions src/themes/bootstrap3/PercentWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ const renderInput = field => {
<div className={className}>
<label className="control-label" htmlFor={'field-'+field.name}>{field.label}</label>
<div className="input-group">
<input {...field.input} type="number" className="form-control" id={'field-'+field.name} required={field.required} placeholder={field.placeholder}/>
<span className="input-group-addon"> %</span>
<input {...field.input} type="number" className="form-control" id={'field-'+field.name} required={field.required} placeholder={field.placeholder}/>
<span className="input-group-addon"> %</span>
</div>
{field.meta.touched && field.meta.error && <span className="help-block">{field.meta.error}</span>}
{field.description && <span className="help-block">{field.description}</span>}
Expand Down
4 changes: 2 additions & 2 deletions src/themes/bootstrap3/oneOfChoiceWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class OneOfChoiceWidget extends Component {
return <option key={options.indexOf(item)} value={idx}>{item.title || idx}</option>
})}
</select>
<div className="container">
<div>
{
this.renderOption()
}
Expand All @@ -45,7 +45,7 @@ class OneOfChoiceWidget extends Component {
renderOption() {
const field = this.props
const schema = field.schema.oneOf[this.state.choice]
return renderField(schema, field.name, field.theme, field.name, field.context)
return renderField(schema, field.fieldName, field.theme, field.prefix, field.context)
}

selectItem(e) {
Expand Down

0 comments on commit 8a18a25

Please sign in to comment.