Skip to content

Commit

Permalink
♻️ #43 - Use Formik FieldArray.
Browse files Browse the repository at this point in the history
  • Loading branch information
Sven van de Scheur committed Jun 6, 2023
1 parent 4549098 commit 1d218c0
Showing 1 changed file with 51 additions and 62 deletions.
113 changes: 51 additions & 62 deletions src/containers/multiple/multiple.container.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import {Component, Description, Label} from '@components';
import {IRenderable, RenderComponent} from '@lib/renderer';
import {IComponentProps, Values} from '@types';
import {IComponentProps, Value, Values} from '@types';
import {ArrayHelpers, FieldArray} from 'formik';
import {ComponentSchema} from 'formiojs';
import React, {useState} from 'react';
import React from 'react';

export interface IMultipleComponent extends ComponentSchema {
key: string;
type: string;
}

Expand All @@ -20,75 +22,62 @@ export interface IMultipleProps extends IComponentProps {
* <RenderComponent/> to render individual instances.
*/
export const Multiple: React.FC<IMultipleProps> = props => {
const {component, form, path, value = [], setValue} = props; // FIXME: Awaits future pr.
const [keys, setKeys] = useState<number[]>([0]);

/** Finds next key by increasing the max key with 1. */
const getKey = (): number => {
if (!keys.length) {
return 0;
}
const max = Math.max(...keys);
return max + 1;
};

/** Add item. */
const add = () => {
setKeys([...keys, getKey()]);
};

/** Remove item at index. */
const remove = (index: number) => {
const _keys = keys.filter((_, i) => i !== index);
const val = value.filter((_, i) => i !== index);
setKeys(_keys);
setValue(path, val);
};
const {component, form, path, value = []} = props; // FIXME: Awaits future pr.

/** Renders individual components utilizing <RenderComponent/>. */
const renderComponents = () =>
keys.map((key, index) => {
// Clone and adjust component to fit nested needs.
const renderable: IRenderable = {
...structuredClone(component),
key: `${path}.${index}`, // Trigger Formik array values.
multiple: false, // Handled by <Multiple/>
description: '', // One description rendered for all components.
label: '', // One label rendered for all components.
};
const renderComponent = (value: Value, index: number, remove: ArrayHelpers['remove']) => {
// Clone and adjust component to fit nested needs.
const renderable: IRenderable = {
...structuredClone(component),
key: `${path}.${index}`, // Trigger Formik array values.
multiple: false, // Handled by <Multiple/>
description: '', // One description rendered for all components.
label: '', // One label rendered for all components.
};

return (
<tr key={key}>
<td>
<RenderComponent component={renderable} form={form} path={path} value={value[index]} />
</td>
<td>
<button onClick={() => remove(index)} aria-controls={renderable.key}>
Remove item
</button>
</td>
</tr>
);
});
return (
<tr key={index}>
<td>
<RenderComponent
component={renderable}
form={form}
path={`${path}.${index}`}
value={value}
/>
</td>
<td>
<button type="button" aria-controls={renderable.key} onClick={() => remove(index)}>
Remove item
</button>
</td>
</tr>
);
};

return (
<Component {...props}>
{props.component.label && (
<Label label={props.component.label} componentId={props.component.key as string} />
)}
<table>
<tbody>{renderComponents()}</tbody>
<tfoot>
<tr>
<td>
<button type="button" onClick={add}>
Add another
</button>
</td>
</tr>
</tfoot>
</table>
<table />
<FieldArray
name={component.key}
render={({push, remove}) => (
<table>
<tbody>
{value.map((value: Value, index: number) => renderComponent(value, index, remove))}
</tbody>
<tfoot>
<tr>
<td>
<button type="button" onClick={() => push(null)}>
Add another
</button>
</td>
</tr>
</tfoot>
</table>
)}
/>
{props.component.description && <Description description={props.component.description} />}
</Component>
);
Expand Down

0 comments on commit 1d218c0

Please sign in to comment.