react-form-builder
react-form-builder copied to clipboard
Add container component
I have a need to add a container that can house components. Could you describe the process for creating that component that even is part of the form builder? I can add that. I feel like it would use some sort of recursion.
My use-case is that I have rules around a group of components or I could auto-repeat the group
For example in email list [ first_name | last_name | email] [ first_name | last_name | email] [ first_name | last_name | email] [ first_name | last_name | email] an another entry could be added to the end.
I'm happy to build it out, I'm just not sure how involved it might be.
@Kiho does this sound reasonable?
I don't like infinity level of recursion, probably you can create 2 sub form components, one for form builder and another for form generator which could be repeatable. Or create repeatable container component based on MultiColumnRow, it might be simpler UI but I think that will be hard to persist data in reasonable format.
He @Kiho hope your well,
I've created the single-column row component using the multi-column row component. I've also tried to add a button that would allow me to add another null child item to the array, but it's not propagating the change. So I tried a few things like triggering store events but I haven't had any luck. Do you know what would be stopping that?
Right now it has some debug output, I'll clean it up when its working.
const OneColumnRow = ({ data, class_name, ...rest }) => {
const {editModeOn = false} = rest;
useEffect(() => {
console.log({ ['data.childItems']: data.childItems }, {data, class_name, rest});
}, [data]);
const className = class_name || 'col-md-12';
if (!data.childItems) {
// eslint-disable-next-line no-param-reassign
data.childItems = [null];
data.isContainer = true;
}
const addAnotherInput = () => {
if(editModeOn) {
console.log("addAnotherInput.before", data.childItems);
data.childItems.push(null);
// store.dispatch('updateOrder', data);
}else{
// duplicate the whole element maybe use a callback. This duplication only
// happens so an array of answers can be collected.
}
}
return (
<div>
<button onClick={addAnotherInput}>
{editModeOn? 'add another input': '+'}
</button>
<MultiColumnRow {...rest} className={className} data={data} />
</div>
);
};
You need to setup updateOrder function in preview.jsx
_onUpdateOrder() {
const newData = this.state.data.slice(0);
store.dispatch('updateOrder', newData);
this.setState({ data: newData });
}
in constructor bind updateOrder to instance
this._onUpdateOrder = this._onUpdateOrder.bind(this);
inject function to components
getElement(item, index) {
...
return <SortableFormElement id={item.id} seq={this.seq} index={index} moveCard={this.moveCard} insertCard={this.insertCard} mutable={false} parent={this.props.parent} editModeOn={this.props.editModeOn} isDraggable={true} key={item.id} sortData={item.id} data={item} getDataById={this.getDataById} setAsChild={this.setAsChild} removeChild={this.removeChild} _onDestroy={this._onDestroy} _onUpdateOrder={this._onUpdateOrder} />;
}
Then you should useState to update data in OneColumnRow
const OneColumnRow = ({ data, class_name, _onUpdateOrder, ...rest }) => {
const { editModeOn = false } = rest;
const [colData, setColData] = useState(data);
useEffect(() => {
console.log({ 'data.childItems': data.childItems }, { data, class_name, rest });
}, [data]);
const className = class_name || 'col-md-12';
if (!data.childItems) {
// eslint-disable-next-line no-param-reassign
data.childItems = [null];
data.isContainer = true;
}
const addAnotherInput = () => {
if (editModeOn) {
console.log('addAnotherInput.before', data.childItems);
data.childItems.push(null);
_onUpdateOrder();
setColData({ ...data });
// store.dispatch('updateOrder', data);
} else {
// duplicate the whole element maybe use a callback. This duplication only
// happens so an array of answers can be collected.
}
};
return (
<div>
<button onClick={addAnotherInput}>
{editModeOn ? 'add another input' : '+'}
</button>
<MultiColumnRow {...rest} className={className} data={colData} />
</div>
);
};
Awesome! I'll do that in the morning ☀️
On Wed, Jun 30, 2021, 10:46 PM Kiho Chang @.***> wrote:
You need to setup updateOrder function in preview.jsx
_onUpdateOrder() { const newData = this.state.data.slice(0); store.dispatch('updateOrder', newData); this.setState({ data: newData }); }
in constructor bind updateOrder to instance
this._onUpdateOrder = this._onUpdateOrder.bind(this);
inject function to components
getElement(item, index) { ... return <SortableFormElement id={item.id} seq={this.seq} index={index} moveCard={this.moveCard} insertCard={this.insertCard} mutable={false} parent={this.props.parent} editModeOn={this.props.editModeOn} isDraggable={true} key={item.id} sortData={item.id} data={item} getDataById={this.getDataById} setAsChild={this.setAsChild} removeChild={this.removeChild} _onDestroy={this._onDestroy} _onUpdateOrder={this._onUpdateOrder} />; }
Then you should useState to update data in OneColumnRow
const OneColumnRow = ({ data, class_name, _onUpdateOrder, ...rest }) => { const { editModeOn = false } = rest; const [colData, setColData] = useState(data);
useEffect(() => { console.log({ 'data.childItems': data.childItems }, { data, class_name, rest }); }, [data]);
const className = class_name || 'col-md-12'; if (!data.childItems) { // eslint-disable-next-line no-param-reassign data.childItems = [null]; data.isContainer = true; }
const addAnotherInput = () => { if (editModeOn) { console.log('addAnotherInput.before', data.childItems); data.childItems.push(null); _onUpdateOrder(); setColData({ ...data }); // store.dispatch('updateOrder', data); } else { // duplicate the whole element maybe use a callback. This duplication only // happens so an array of answers can be collected. } };
return (
<button onClick={addAnotherInput}> {editModeOn ? 'add another input' : '+'} <MultiColumnRow {...rest} className={className} data={colData} />);};— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Kiho/react-form-builder/issues/140#issuecomment-871869625, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA64TKNPI75M5R57XCJV4BLTVPJI7ANCNFSM47EDWL5A .
Wow, this works perfectly, thank you so much!
I just need to figure out now how to make inputs in the group save to an array. I have a need when filling out the form to be able to duplicate the whole group.
so input name first_name
in the group name user
would save something like this form.user[0].first_name
and form.user[1].first_name