Make form sub-property optional; Handle extra queries in FormWrapper; remove resolveAs fragment shape "guessing" code

This commit is contained in:
SachaG 2017-12-28 11:31:55 +09:00
parent aefefc9a7a
commit 8d0cc3e5e2
4 changed files with 52 additions and 31 deletions

View file

@ -144,8 +144,9 @@ class Form extends Component {
}
// replace value by prefilled value if value is empty
if (fieldSchema.form && fieldSchema.form.prefill) {
const prefilledValue = typeof fieldSchema.form.prefill === "function" ? fieldSchema.form.prefill.call(fieldSchema) : fieldSchema.form.prefill;
const prefill = fieldSchema.prefill || fieldSchema.form && fieldSchema.form.prefill;
if (prefill) {
const prefilledValue = typeof prefill === "function" ? prefill.call(fieldSchema) : prefill;
if (!!prefilledValue && !field.value) {
field.prefilledValue = prefilledValue;
field.value = prefilledValue;
@ -162,8 +163,9 @@ class Form extends Component {
}
// add options if they exist
if (fieldSchema.form && fieldSchema.form.options) {
field.options = typeof fieldSchema.form.options === "function" ? fieldSchema.form.options.call(fieldSchema, this.props) : fieldSchema.form.options;
const fieldOptions = fieldSchema.options || fieldSchema.form && fieldSchema.form.options;
if (fieldOptions) {
field.options = typeof fieldOptions === "function" ? fieldOptions.call(fieldSchema, this.props) : fieldOptions;
// in case of checkbox groups, check "checked" option to populate value
if (!field.value) {
@ -171,12 +173,15 @@ class Form extends Component {
}
}
if (fieldSchema.form) {
for (const prop in fieldSchema.form) {
if (prop !== 'prefill' && prop !== 'options' && fieldSchema.form.hasOwnProperty(prop)) {
field[prop] = typeof fieldSchema.form[prop] === "function" ?
fieldSchema.form[prop].call(fieldSchema) :
fieldSchema.form[prop];
// add any properties specified in fieldProperties or form as extra props passed on
// to the form component
const fieldProperties = fieldSchema.fieldProperties || fieldSchema.form;
if (fieldProperties) {
for (const prop in fieldProperties) {
if (prop !== 'prefill' && prop !== 'options' && fieldProperties.hasOwnProperty(prop)) {
field[prop] = typeof fieldProperties[prop] === "function" ?
fieldProperties[prop].call(fieldSchema) :
fieldProperties[prop];
}
}
}

View file

@ -76,22 +76,6 @@ class FormWrapper extends PureComponent {
mutationFields = _.intersection(mutationFields, fields);
}
// resolve any array field with resolveAs as fieldName{_id} -> why?
/*
- string field with no resolver -> fieldName
- string field with a resolver -> fieldName
- array field with no resolver -> fieldName
- array field with a resolver -> fieldName{_id}
*/
const mapFieldNameToField = fieldName => {
const field = this.getSchema()[fieldName];
return field.resolveAs && field.type.definitions[0].type === Array
? `${fieldName}{_id}` // if it's a custom resolver, add a basic query to its _id
: fieldName; // else just ask for the field name
}
queryFields = queryFields.map(mapFieldNameToField);
mutationFields = mutationFields.map(mapFieldNameToField);
// generate query fragment based on the fields that can be edited. Note: always add _id.
const generatedQueryFragment = gql`
fragment ${fragmentName} on ${this.props.collection.typeName} {
@ -107,11 +91,29 @@ class FormWrapper extends PureComponent {
}
`
// default to generated fragments
let queryFragment = generatedQueryFragment;
let mutationFragment = generatedMutationFragment;
// if queryFragment or mutationFragment props are specified, accept either fragment object or fragment string
if (this.props.queryFragment) {
queryFragment = typeof this.props.queryFragment === 'string' ? gql`${this.props.queryFragment}` : this.props.queryFragment;
}
if (this.props.mutationFragment) {
mutationFragment = typeof this.props.mutationFragment === 'string' ? gql`${this.props.mutationFragment}` : this.props.mutationFragment;
}
// if any field specifies extra queries, add them
const extraQueries = _.compact(queryFields.map(fieldName => {
const field = this.getSchema()[fieldName];
return field.query
}));
// get query & mutation fragments from props or else default to same as generatedFragment
// note: mutationFragment should probably always be specified in props
return {
queryFragment: this.props.queryFragment || generatedQueryFragment,
mutationFragment: this.props.mutationFragment || generatedMutationFragment,
queryFragment,
mutationFragment,
extraQueries,
};
}
@ -126,6 +128,8 @@ class FormWrapper extends PureComponent {
// props received from parent component (i.e. <Components.SmartForm/> call)
const parentProps = this.props;
const { queryFragment, mutationFragment, extraQueries } = this.getFragments();
// props to pass on to child component (i.e. <Form />)
const childProps = {
formType: this.getFormType(),
@ -136,7 +140,8 @@ class FormWrapper extends PureComponent {
const queryOptions = {
queryName: `${prefix}FormQuery`,
collection: this.props.collection,
fragment: this.getFragments().queryFragment,
fragment: queryFragment,
extraQueries,
fetchPolicy: 'network-only', // we always want to load a fresh copy of the document
enableCache: false,
};
@ -144,7 +149,7 @@ class FormWrapper extends PureComponent {
// options for withNew, withEdit, and withRemove HoCs
const mutationOptions = {
collection: this.props.collection,
fragment: this.getFragments().mutationFragment,
fragment: mutationFragment,
};
// if this is an edit from, load the necessary data using the withDocument HoC

View file

@ -12,6 +12,9 @@ if (typeof SimpleSchema !== "undefined") {
'beforeComponent',
'afterComponent',
'placeholder',
'options',
'query',
'fieldProperties',
]);
}

View file

@ -10,6 +10,14 @@ Get a fragment's name from its text
*/
export const extractFragmentName = fragmentText => fragmentText.match(/fragment (.*) on/)[1];
/*
Get a query resolver's name from its text
*/
export const extractResolverName = resolverText => resolverText.trim().substr(0, resolverText.trim().indexOf('{'));
/*
Register a fragment, including its text, the text of its subfragments, and the fragment object