mirror of
https://github.com/vale981/Vulcan
synced 2025-03-06 01:51:40 -05:00
refactor + simplify nova:forms logic
This commit is contained in:
parent
0c76519954
commit
7f8a38a2a1
4 changed files with 59 additions and 107 deletions
|
@ -68,10 +68,6 @@ A number corresponding to the position of the property's field inside the form.
|
|||
|
||||
The main `NovaForm` components makes the following objects available as context to all its children:
|
||||
|
||||
#### `currentValues`
|
||||
|
||||
An object containing all the current values of the form.
|
||||
|
||||
#### `prefilledValues`
|
||||
|
||||
An object containing optional prefilled properties.
|
||||
|
|
|
@ -13,75 +13,48 @@ const Textarea = FRC.Textarea;
|
|||
|
||||
class FormComponent extends Component {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
renderComponent() {
|
||||
|
||||
({fieldName, field, labelFunction, document} = this.props);
|
||||
// if control is a React component, use it
|
||||
if (typeof this.props.control === "function") {
|
||||
|
||||
let options = [];
|
||||
if (field.autoform && field.autoform.options) {
|
||||
options = typeof field.autoform.options === "function" ? field.autoform.options() : field.autoform.options;
|
||||
}
|
||||
return <this.props.control {...this.props} />
|
||||
|
||||
const value = document && Utils.deepValue(document, fieldName) ? Utils.deepValue(document, fieldName) : "";
|
||||
const label = typeof labelFunction === "function" ? labelFunction(fieldName) : fieldName;
|
||||
} else { // else pick a predefined component
|
||||
|
||||
const inputProps = {
|
||||
key: fieldName,
|
||||
name: fieldName,
|
||||
value: value,
|
||||
label: label
|
||||
};
|
||||
|
||||
if (typeof field.control === "function") {
|
||||
|
||||
return <field.control {...inputProps} />
|
||||
|
||||
} else {
|
||||
|
||||
switch (field.control) {
|
||||
switch (this.props.control) {
|
||||
case "text":
|
||||
return <Input {...inputProps} type="text" />;
|
||||
return <Input {...this.props} type="text" />;
|
||||
case "textarea":
|
||||
return <Textarea {...inputProps} />;
|
||||
return <Textarea {...this.props} />;
|
||||
case "checkbox":
|
||||
return <Checkbox {...inputProps}/>;
|
||||
return <Checkbox {...this.props} />;
|
||||
// note: checkboxgroup cause React refs error
|
||||
case "checkboxgroup":
|
||||
return <CheckboxGroup {...inputProps} options={options} />;
|
||||
return <CheckboxGroup {...this.props} />;
|
||||
case "radiogroup":
|
||||
return <RadioGroup {...inputProps} options={options} />;
|
||||
return <RadioGroup {...this.props} />;
|
||||
case "select":
|
||||
return <Select {...inputProps} options={options} />;
|
||||
return <Select {...this.props} />;
|
||||
default:
|
||||
return <Input {...inputProps} type="text" />;
|
||||
return <Input {...this.props} type="text" />;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.field.control === "none") {
|
||||
return null;
|
||||
} else {
|
||||
return (
|
||||
<div className={"input-"+fieldName}>
|
||||
{this.renderComponent()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return <div className={"input-"+this.props.name}>{this.renderComponent()}</div>
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FormComponent.propTypes = {
|
||||
fieldName: React.PropTypes.string,
|
||||
field: React.PropTypes.object,
|
||||
labelFunction: React.PropTypes.func,
|
||||
document: React.PropTypes.object
|
||||
name: React.PropTypes.string,
|
||||
label: React.PropTypes.string,
|
||||
value: React.PropTypes.any,
|
||||
options: React.PropTypes.any,
|
||||
control: React.PropTypes.any
|
||||
}
|
||||
|
||||
export default FormComponent;
|
||||
|
|
|
@ -11,14 +11,12 @@ class NovaForm extends Component{
|
|||
super(props);
|
||||
this.submitForm = this.submitForm.bind(this);
|
||||
this.methodCallback = this.methodCallback.bind(this);
|
||||
this.updateState = this.updateState.bind(this);
|
||||
this.addToPrefilledValues = this.addToPrefilledValues.bind(this);
|
||||
this.throwError = this.throwError.bind(this);
|
||||
this.clearErrors = this.clearErrors.bind(this);
|
||||
this.state = {
|
||||
disabled: false,
|
||||
errors: [],
|
||||
currentValues: this.props.document
|
||||
errors: []
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -28,7 +26,7 @@ class NovaForm extends Component{
|
|||
}
|
||||
|
||||
// get relevant fields
|
||||
getFields() {
|
||||
getFieldNames() {
|
||||
const collection = this.props.collection;
|
||||
const fields = this.getFormType() === "edit" ? collection.getEditableFields(this.props.currentUser) : collection.getInsertableFields(this.props.currentUser);
|
||||
return fields;
|
||||
|
@ -54,31 +52,17 @@ class NovaForm extends Component{
|
|||
return <div className="form-errors">{this.state.errors.map(message => <Flash key={message} message={message}/>)}</div>
|
||||
}
|
||||
|
||||
// whenever the form values change, keep track of them in the state
|
||||
updateState(e) {
|
||||
// e can sometimes be event, sometims be currentValue
|
||||
// see https://github.com/christianalfoni/formsy-react/issues/203
|
||||
if (e.stopPropagation) {
|
||||
e.stopPropagation();
|
||||
} else {
|
||||
this.setState({
|
||||
currentValues: e
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// add something to the state
|
||||
// add something to prefilled values
|
||||
addToPrefilledValues(property) {
|
||||
this.setState({
|
||||
prefilledValues: {...this.state.prefilledValues, ...property}
|
||||
});
|
||||
}
|
||||
|
||||
// pass on form values as context to all child components for easy access
|
||||
// pass on context to all child components
|
||||
getChildContext() {
|
||||
return {
|
||||
throwError: this.throwError,
|
||||
currentValues: this.state.currentValues,
|
||||
prefilledValues: this.state.prefilledValues,
|
||||
addToPrefilledValues: this.addToPrefilledValues
|
||||
};
|
||||
|
@ -122,7 +106,7 @@ class NovaForm extends Component{
|
|||
submitForm(data) {
|
||||
this.setState({disabled: true});
|
||||
|
||||
const fields = this.getFields();
|
||||
const fields = this.getFieldNames();
|
||||
const collection = this.props.collection;
|
||||
|
||||
// if there's a submit callback, run it
|
||||
|
@ -163,28 +147,41 @@ class NovaForm extends Component{
|
|||
}
|
||||
|
||||
render() {
|
||||
|
||||
// build fields array by iterating over the list of field names
|
||||
let fields = this.getFieldNames().map(fieldName => {
|
||||
|
||||
// get schema for the current field
|
||||
const fieldSchema = this.props.collection.simpleSchema()._schema[fieldName]
|
||||
|
||||
const document = this.props.document;
|
||||
const collection = this.props.collection;
|
||||
const fields = this.getFields();
|
||||
// add name, label, and type properties
|
||||
let field = {
|
||||
name: fieldName,
|
||||
label: (typeof fieldSchema.labelFunction === "function") ? fieldSchema.labelFunction(fieldName) : fieldName,
|
||||
type: fieldSchema.type,
|
||||
control: fieldSchema.control
|
||||
}
|
||||
|
||||
const style = {
|
||||
maxWidth: "800px",
|
||||
width: "100%"
|
||||
}
|
||||
// add value
|
||||
field.value = this.props.document && Utils.deepValue(this.props.document, fieldName) ? Utils.deepValue(this.props.document, fieldName) : "";
|
||||
|
||||
// add options if they exist
|
||||
if (fieldSchema.autoform && fieldSchema.autoform.options) {
|
||||
field.options = typeof fieldSchema.autoform.options === "function" ? fieldSchema.autoform.options() : fieldSchema.autoform.options;
|
||||
}
|
||||
|
||||
return field;
|
||||
|
||||
});
|
||||
|
||||
// remove fields where control = "none"
|
||||
fields = _.reject(fields, field => field.control === "none");
|
||||
|
||||
return (
|
||||
<div className={"document-"+this.getFormType()} style={style}>
|
||||
<Formsy.Form onSubmit={this.submitForm} onChange={this.updateState} disabled={this.state.disabled} ref="form">
|
||||
<div className={"document-"+this.getFormType()}>
|
||||
<Formsy.Form onSubmit={this.submitForm} disabled={this.state.disabled} ref="form">
|
||||
{this.renderErrors()}
|
||||
{fields.map(fieldName => <FormComponent
|
||||
key={fieldName}
|
||||
className={"input-"+fieldName}
|
||||
fieldName={fieldName}
|
||||
field={collection.simpleSchema()._schema[fieldName]}
|
||||
labelFunction={this.props.labelFunction}
|
||||
document={document}
|
||||
/>)}
|
||||
{fields.map(field => <FormComponent key={field.name} {...field} />)}
|
||||
<Button type="submit" bsStyle="primary">Submit</Button>
|
||||
</Formsy.Form>
|
||||
</div>
|
||||
|
@ -210,10 +207,9 @@ NovaForm.contextTypes = {
|
|||
}
|
||||
|
||||
NovaForm.childContextTypes = {
|
||||
currentValues: React.PropTypes.object,
|
||||
prefilledValues: React.PropTypes.object,
|
||||
throwError: React.PropTypes.func,
|
||||
addToPrefilledValues: React.PropTypes.func
|
||||
addToPrefilledValues: React.PropTypes.func,
|
||||
throwError: React.PropTypes.func
|
||||
}
|
||||
|
||||
module.exports = NovaForm;
|
||||
|
|
|
@ -31,11 +31,7 @@ Posts.schema = new SimpleSchema({
|
|||
insertableIf: Users.is.admin,
|
||||
editableIf: Users.is.admin,
|
||||
publish: true,
|
||||
control: "datepicker",
|
||||
autoform: {
|
||||
group: 'admin',
|
||||
type: "bootstrap-datetimepicker"
|
||||
}
|
||||
control: "datepicker"
|
||||
},
|
||||
/**
|
||||
URL
|
||||
|
@ -61,9 +57,7 @@ Posts.schema = new SimpleSchema({
|
|||
editableIf: Users.is.ownerOrAdmin,
|
||||
control: PrefilledTitle,
|
||||
publish: true,
|
||||
autoform: {
|
||||
order: 20
|
||||
}
|
||||
order: 20
|
||||
},
|
||||
/**
|
||||
Slug
|
||||
|
@ -84,10 +78,7 @@ Posts.schema = new SimpleSchema({
|
|||
editableIf: Users.is.ownerOrAdmin,
|
||||
control: PrefilledBody,
|
||||
publish: true,
|
||||
autoform: {
|
||||
rows: 5,
|
||||
order: 30
|
||||
}
|
||||
order: 30
|
||||
},
|
||||
/**
|
||||
HTML version of the post body
|
||||
|
@ -164,11 +155,7 @@ Posts.schema = new SimpleSchema({
|
|||
insertableIf: Users.is.admin,
|
||||
editableIf: Users.is.admin,
|
||||
control: "checkbox",
|
||||
publish: true,
|
||||
autoform: {
|
||||
group: 'admin',
|
||||
leftLabel: "Sticky"
|
||||
}
|
||||
publish: true
|
||||
},
|
||||
/**
|
||||
Whether the post is inactive. Inactive posts see their score recalculated less often
|
||||
|
|
Loading…
Add table
Reference in a new issue