Closed wahiche closed 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?
react-router
but you can use anything. You just need to follow the interface. Here is an example with react-router
and another with react-navigation
https://github.com/CareLuLu/react-native-web-ui-components#mobileWhy 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.
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
@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.
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.
@wahiche great! Glad I could help :)
@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?
@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]),
},
}),
},
},
};
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?
@wahiche a checkboxes
widget can definitely be created. Would you like to create PR?
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.
That would be great!
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.