Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] Pass the modifier along with the document #66

Closed
serkandurusoy opened this issue Jul 11, 2016 · 5 comments
Closed

[Feature Request] Pass the modifier along with the document #66

serkandurusoy opened this issue Jul 11, 2016 · 5 comments
Assignees
Labels
Type: Feature New features and feature requests

Comments

@serkandurusoy
Copy link
Contributor

Form events such as onSubmit currently only passes doc but there are cases where a modifier is more suitable, especially for update forms

Consider a schema where all the fields are optional

collection = new Mongo.Collection('sample')

schema = new SimpleSchema({
  foo: {type: String, optional: true},
  bar: {type: String, optional: true},
})

collection.attachSchema(schema)

and consider this document:

doc = {
   foo: "some value"
}

<AutoForm onSubmit={ doc => collection.update( this.props.docId, { $set: {...doc} } ) } model={doc} schema={schema} />

Now if you delete the value of foo and submit, this will throw error saying that after filtering out, modifier is empty.

This is expected because collection2 trims trailing spaces, deletes empty fields, runs autovalues etc before doing the actual insert, at which time doc becomes {} so instead, we need to $unset: { foo: '' } so to mitigate this, I am currently doing this:

function handler(docId,doc) {
  const unsetDoc = schema.objectKeys
    .filter( key => !doc[key] )
    .map( key => ( {[key]: ''} ) )
    .reduce( (obj, unset) => {
      obj[Object.keys(unset)[0]] = unset[Object.keys(unset)[0]];
      return obj;
    }, {} );

  let modifier = {};

  if (Object.keys(doc).length > 0) {
    modifier.$set = {...doc}
  }

  if (Object.keys(unsetDoc).length > 0) {
    modifier.$unset = {...unsetDoc}
  }

  collection.update(docId, modifier);

}

But it would be awesome if onSubmit were able to provide me the modifier out of box, such that, the following would work:

<AutoForm 
  onSubmit={ (doc,modifier) => handler(this.props.docId, modifier) } 
  model={doc} 
  schema={schema} />

Now the original autoform has solutions similar to this:

  • update form automatically handles this, providing a modifier and passing it on to the collection
  • method update form which provides you a modifier and document id which you can pass on to your methods
  • hooks where onSubmit passes a doc and a modifier and a formToModifier hook which directly takes the modifier whenever form fields change (like an onChange for update forms)

For code reference, you can take a look at here and here

@serkandurusoy serkandurusoy changed the title [Feature] [Feature Request] Pass the modifier along with the document Jul 11, 2016
@radekmie radekmie self-assigned this Jul 11, 2016
@radekmie radekmie added the Type: Feature New features and feature requests label Jul 11, 2016
@radekmie
Copy link
Contributor

radekmie commented Jul 11, 2016

Finally!
I've waited so long to get a possibility to provide an example with extending BaseForm. Let's create a ModifierForm (okay, it will be AutoValidatedQuickModifierForm)!

import {BaseForm} from 'uniforms';
import {AutoForm} from 'uniforms-semantic'; // or any other

const Modifier = parent => class extends parent {
    static Modifier = Modifier;

    static displayName = `Modifier${parent.displayName}`;

    onSubmit (event) {
        if (event) {
            event.preventDefault();
            event.stopPropagation();
        }

        if (this.props.onSubmit) {
            // You can also omit unchanged keys.
            const $set = this.getModel();
            const $unset = this.getChildContextSchema().getSubfields()
                .filter(key => !$set[key])
                .reduce((acc, key) => ({...acc, [key]: ''}), {})

            this.props.onSubmit({
                ...Object.keys($set).length   > 0 && {$set},
                ...Object.keys($unset).length > 0 && {$unset}
            });
        }
    }
};

// This might seem a little bit crazy, but we have to override BaseForm#onSubmit
// If you are using for example Bootstrap3, then change AutoForm.Semantic to AutoForm.Bootstrap3
export default AutoForm.Auto(AutoForm.Validated(AutoForm.Quick(AutoForm.Semantic(Modifier(BaseForm)))));

From here, you can easily create an UpdateForm with direct collection support.

Note: This API will remain unchanged, but some shortcuts are planned.

@serkandurusoy
Copy link
Contributor Author

Whoa! This is a precious gem! It never occured to me to extend from existing form components like this, wow!

@GoaGit
Copy link

GoaGit commented Aug 8, 2016

You provide an excellent explanation @radekmie about how to construct a modifier form. What is the proper way to actually use the modifier form you created in the example, given a schema, model and function? My first idea is would be:

import UpdateForm from '/path/to/updateform.js';
import React, { Component } from 'react';

class Update extends Component{
...

render(){

...

<UpdateForm 
  schema={SomeImportedSchema}
  model={SomeProvidedModel}
  onSubmit={SomeProvidedFunction}
/>

...

}

This does not render a form. Do I overlook something?

@radekmie
Copy link
Contributor

radekmie commented Aug 8, 2016

No, @GoaGit, it's my fault - I wrote it as a concept and haven't tested it. Now I've done and I've just updated that implementation.

@GoaGit
Copy link

GoaGit commented Aug 8, 2016

That's really awesome @radekmie. You've created a very elegant solution. Looking forward to be able to use it.

@radekmie radekmie moved this to Closed in Open Source Nov 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Feature New features and feature requests
Projects
Archived in project
Development

No branches or pull requests

3 participants