CareLuLu / react-native-web-jsonschema-form

37 stars 2 forks source link

In need of some working examples, documentation, please help. #173

Closed wahiche closed 4 years ago

wahiche commented 4 years ago

My team have recently decided to investigate the feasibility of using JSON forms in our Expo RN project. We came across your implementation and are very excited that you have put together such a large and comprehensive tool.

I know that in your readme you have said that the documentation is a WIP. But it does make implementation extremely difficult.

First a comment:

I tried to get it working on RN with your basic example code and it did not work. I had to make a lot of changes to it to make it work, but did finally get it. I would suggest making that example actually viable for people to get a "basic" example up and running.

I have a few questions that maybe you can help me with:

Does it render the form in a webView? Why is the UIProvider important, and why does it need to useHistory? Why can't the form just work as a component on it's own, where you just feed in the schemas and data? How do I use a custom widget? What is the the expected object that I need to send? import MyRadioComponent from '/components/myRadioComponent'; import MyCheckboxComponent from '/components/myCheckboxComponent '; { radio: MyRadioComponent, checkbox: MyCheckboxComponent or () => <MyCheckboxComponent /> } Is there any possibility of getting documentation in the near future, of all the components, widgets, props etc... that are actually available?

I respect that you have put a lot of time and effort, that is very obvious, and I am not complaining, I am just finding it increasingly difficult to figure things out, by sifting through code, rather than documentation.

The development world thanks all of you who put the time and effort that we don't into these wonderful repos.

Thank you.

CareLuLu-Gabriel commented 4 years ago

Hi @wahiche, I appreciate the feedback!

I didn't know the examples weren't working. We have a full app example here https://github.com/CareLuLu/react-native-web-skeleton and hosted here https://www.carelulu.com/react-native-web-example. Would you mind listing the examples that aren't working?

In regards to your questions:

Does it render the form in a webView?

No. It uses react-native-web and react-native to render the components. We created a more generic library that provides the main components we need: https://github.com/CareLuLu/react-native-web-ui-components. Things like Checkbox, TextInput, and many others.

Why is the UIProvider important, and why does it need to useHistory?

Why can't the form just work as a component on its own, where you just feed in the schemas and data?

Not sure if I understood your question. The form renders the components solely based on schema and uiSchema. Aside from that, the form provides an API to handle events such as onSubmit, onSuccess, onError, etc. But the implementation of the submission varies from app to app. Here is an example:

https://github.com/CareLuLu/react-native-web-skeleton/blob/master/src/components/Form.js: This is a general form wrapper that is used throughout the app. Then each specific form is as simple as this https://github.com/CareLuLu/react-native-web-skeleton/blob/master/src/components/modals/Login.js.

How do I use a custom widget? What is the the expected object that I need to send?

Here is an example of a custom widget:

import React from 'react';
import PropTypes from 'prop-types';
import { Text } from 'react-native-web-ui-components';
import moment from 'moment-timezone';

const getTime = value => moment().tz(value || 'UTC').format('M/D/YYYY [at] h:mma [(]dddd[)]');

class ClockWidget extends React.Component {
  static propTypes = {
    value: PropTypes.any, // eslint-disable-line
  };

  constructor(props) {
    super(props);

    const { value } = this.props;
    this.state = {
      time: getTime(value),
    };
  }

  componentDidMount() {
    this.timer = setInterval(this.tick, 1000);
  }

  componentWillUnmount() {
    if (this.timer) {
      clearInterval(this.timer);
    }
  }

  tick = () => {
    const { value } = this.props;
    this.setState({ time: getTime(value) });
  };

  render() {
    const { time } = this.state;
    return <Text>{time}</Text>;
  }
}

export default ClockWidget;

Then you can send an object of custom widgets to the form:

const MyForm = props => (
  <Form
    {...props}
    widgets={{ ClockWidget }}
  />
);

Your uiSchema can use the custom widget as:

const uiSchema = {
  myCustomAttribute: {
    'ui:widget': 'clock', // ClockWidget => ucfirst('ClockWidget').replace(/Widget$/, '');
  }
}

Is there any possibility of getting documentation in the near future, of all the components, widgets, props etc... that are actually available?

Unfortunately, we haven't had the time yet. We'd love help with that though.

wahiche commented 4 years ago

Thank you for such a quick response. I have been going over this the past couple of nights, and I am still a bit confused when it comes to using the custom components.

From what I am to understand the

component is required to included the schema, at the very least. Your example does not mention the schema portion. Beside all of that what is the expectation of a widget?

If I wanted to use my version of a radio button and not the one that you provided, how would I set that up?

Import MyRadioButton from '../components/MyRadioButton'

const schema = {
   ...
    "properties":{
      "customAttribute" : {
       "type": "boolean"
      }
   }
}
const uiSchema = {
   ...,
   "customAttribute: : {
      "ui:widget": "MyRadioButton",
   }
}

at this point I am a bit lost. How do I get specific content for the options to display in the component that I created, so lets say instead of Yes/No as the options I wanted up/down. How do I style them to fit my styles? What about handling the submission of the form elements, how do I handle that?

CareLuLu-Gabriel commented 4 years ago

@wahiche you're right the schema is the least you need to give. That's the JSON that defines the form, without a schema, you will see an empty form. Could you please let me know what example you're talking about so I can clarify?

If I wanted to use my version of a radio button and not the one that you provided, how would I set that up? First, I'd like to clarify if you just want to make minor changes, you may simply use the style, theme, and other custom properties that vary from component to component. These are done through the uiSchema.

For example:

const schema = {
  type: 'object',
  properties: {
    rememberPassword: { type: 'boolean' },
  },
};
const uiSchema = {
  rememberPassword: {
    'ui:title': 'Remember password?',
    'ui:widget': 'radio',
    'ui:widgetProps': {
      style: { backgroundColor: 'black' },
    },
    'ui:containerProps': {
      style: { paddingTop: 10 },
    },
  },
};

If you still want to create your own widget, you need to send the widgets to the form:

const MyRadioButom = ({
  name,
  value,
  errors,
  onChange,
}) => (
  <View>
    <YesComponent onPress={() => onChange(true, name)} />
    <NoComponent onPress={() => onChange(false, name)} />
    {errors.map(error => <ErrorComponent key={error} error={error} />}
  </View>
);

MyRadioButton.propTypes = {
  name: PropTypes.string.isRequired,
  onChange: PropTypes.func.isRequired,
  errors: PropTypes.array,
  value: PropTypes.any,
};

MyRadioButton.defaultProps = {
  errors: [],
  value: false,
};

const schema = {
  type: 'object',
  properties: {
    rememberPassword: { type: 'boolean' },
  },
};

const uiSchema = {
  rememberPassword: {
    'ui:widget': 'myRadioButtom', // lowercase first letter and remove 'Widget' from the end
    'ui:widgetProps': {
      // if you want to pass anything special down 
    }, 
  },
};

const MyForm = props => (
  <Form
    {...props}
    schema={schema}
    uiSchema={uiSchema}
    widgets={{ MyRadioButtom }}
  />
);

This library was based on https://github.com/rjsf-team/react-jsonschema-form and they do have documentation. We do have a few different properties but the basic ones are the same.

wahiche commented 4 years ago

Thank you again, I worked with a colleague to figure out most of how the custom widget works. But your examples here are just fantastic. I am going to continue to play with it and see how it goes, if I can just style them as I want them, then I am way better of than using a custom component.

Thanks again, your time and expertise is very appreciated.

CareLuLu-Gabriel commented 4 years ago

@wahiche great! Glad I could help :)

wahiche commented 4 years ago

@CareLuLu-Gabriel Sorry to ask so many questions, but I was wondering about the difference between Radio and Checkbox.

When set as Boolean for either of them, with Radio buttons I get two options. How do I setup a group of checkboxes with labels, where you can choose one or many?

CareLuLu-Gabriel commented 4 years ago

@wahiche, to have a list of checkboxes in which you choose more than one, the schema must be an array.

const favorites = ['Chocolate', 'Ice cream', 'Cake'];

const schema = {
  type: 'object',
  properties: {
    favorites: {
      type: 'array',
      items: {
        type: 'string',
      },
    }
  },
};

const uiSchema = {
 favorites: {
    'ui:title': 'Favorite foods',
    'ui:options': {
      addable: false,
      orderable: false,
      removable: false,
      minimumNumberOfItems: favorites.length,
    },
    items: {
      // The `ui:iterate` allows you to define the uiSchema for each item of the array.
      // The default is to have a list of TextInput.
      'ui:iterate': (i, { values }) => ({
        'ui:title': false,
        'ui:widget': 'checkbox',
        'ui:widgetProps': {
          text: favorites[i],
          value: favorites[i],
          checked: (values.favorites || []).includes(favorites[i]),
        },
      }),
    },
  },
};
Screen Shot 2020-10-08 at 12 24 25 PM
wahiche commented 4 years ago

Thanks for the response. So after further investigation, and seeing another comment on another issue we did notice that this was the way to work around this issue. The one comment we had was that this would mean that the person providing the JSON Schemas would have to include this in every checkbox group, we may have multiple, and it has to be in the uiSchema.

Based on your expertise of building this library, do you think that a checkboxes widget could be created to do this? Or is this the only way based on how the library was developed?

CareLuLu-Gabriel commented 4 years ago

@wahiche a checkboxes widget can definitely be created. Would you like to create PR?

wahiche commented 4 years ago

Well actually that was the thought that my coworker and I were thinking. Basically trying to take the default one from the JSON schema form repo and porting it to React Native. He is much better than me at deciphering what is going on, I get confused easily.

CareLuLu-Gabriel commented 4 years ago

That would be great!