Reputation: 193
The exercise model looks like this.
{
amount: "",
reps: [],
id: "",
};
I'm having difficulty storing the reps
array from the text inputs and saving it into State
I think the problem is the onChanged
method, setting the reps
array value to the corresponding text inputs.
// update exercises with new amount
const onChanged = (e) => {
const exerciseIndex = e.target.dataset.index;
const updatedExercises = [...exercises];
updatedExercises[exerciseIndex].amount = e.target.value;
updatedExercises[exerciseIndex].reps = e.target.value;
setExercises(updatedExercises);
};
...
Amount
<TextInput
value={exercise.amount}
data-index={index}
onChange={onChanged}
></TextInput>
<TableCell>
<Flex justifyContent={"center"}>1</Flex>
<TextInput
value={exercise.reps[0]}
data-index={index}
onChange={onChanged}
></TextInput>
</TableCell>
<TableCell>
<Flex justifyContent={"center"}>2</Flex>
<TextInput
value={exercise.reps[1]}
data-index={index}
onChange={onChanged}
></TextInput>
</TableCell>
...
Saving the amount
value is working correctly.
Whole page snippet is here.
// @ts-nocheck
import { React, useState, useEffect } from "react";
import {
Button,
EditorToolbarButton,
SkeletonBodyText,
SkeletonContainer,
Table,
TableBody,
TableRow,
TableCell,
TextInput,
Paragraph,
RadioButton,
SectionHeading,
Flex,
RadioButtonField,
} from "@contentful/forma-36-react-components";
import { FieldExtensionSDK } from "contentful-ui-extensions-sdk";
interface FieldProps {
sdk: FieldExtensionSDK;
}
const ExercisesList = (props: FieldProps) => {
const fieldValue = props.sdk.field.getValue();
const [exercises, setExercises] = useState(fieldValue || []);
// use contentful's builtin auto-resizer
useEffect(() => {
props.sdk.window.startAutoResizer();
});
// check for unresolved names and fetch them from contenful if neccessary
useEffect(() => {
const exercisesWithoutName = exercises.filter((exercise) => !exercise.name);
if (!exercisesWithoutName.length) {
return;
}
const ids = exercises.map((exercise) => exercise.id);
props.sdk.space.getEntries({ "sys.id[in]": ids }).then((queryResult) => {
let populatedExercises = exercises.map((exercise) => {
const resultForCurrentExercise = queryResult.items
.filter((entry) => entry.sys.id === exercise.id)
.pop();
return {
name: resultForCurrentExercise
? resultForCurrentExercise.fields.title["en-US"]
: "",
...exercise,
};
});
setExercises(populatedExercises);
});
}, [exercises, props.sdk.space]);
// update contentful field value whenever exercises data changes
useEffect(() => {
const sanitizedExercises = exercises.map((exercise) => {
console.log("exercise ", exercise);
return {
amount: exercise.amount,
reps: [exercise.reps],
id: exercise.id,
};
});
props.sdk.field.setValue(sanitizedExercises);
}, [exercises, props.sdk.field]);
// open entry selection dialog and append selected entries to the end of our list
const onAddButtonClicked = () => {
props.sdk.dialogs
.selectMultipleEntries({ contentTypes: ["exercise"] })
.then((selectedExercises) => {
setExercises([
...exercises,
...selectedExercises.map((exercise) => {
console.log("...exercises", ...exercises);
return {
amount: "",
reps: [""],
id: exercise.sys.id,
key: `${exercise.sys.id}-${Math.floor(Math.random() * 100000)}`,
};
}),
]);
props.sdk.field.setValue(exercises);
})
.catch(() => {
/* do nothing */
});
};
// update exercises with new amount
const onChanged = (e) => {
const exerciseIndex = e.target.dataset.index;
const updatedExercises = [...exercises];
updatedExercises[exerciseIndex].amount = e.target.value;
updatedExercises[exerciseIndex].reps = e.target.value;
setExercises(updatedExercises);
};
// remove exercise from list
const onDeleteButtonClicked = (e) => {
let actualTarget = e.target;
while (!actualTarget.dataset.index || actualTarget.id === "root") {
actualTarget = actualTarget.parentNode;
}
if (actualTarget.id === "root") {
return;
}
const exerciseIndex = parseInt(actualTarget.dataset.index);
const updatedExercises = exercises.filter(
(_, index) => index !== exerciseIndex
);
setExercises(updatedExercises);
};
return (
<section>
<div>
<Table>
<TableBody>
{exercises.map((exercise, index) => {
return (
<>
<TableRow key={exercise.key}>
<TableCell style={{ width: "150px" }}>
{exercise.name ? (
exercise.name
) : (
<SkeletonContainer svgHeight="20">
<SkeletonBodyText numberOfLines="1"></SkeletonBodyText>
</SkeletonContainer>
)}
</TableCell>
Amount
<TextInput
value={exercise.amount}
data-index={index}
onChange={onChanged}
></TextInput>
<TableCell style={{ width: "50px" }}>
<Flex flexDirection={"column"} justifyContent={"center"}>
<Paragraph
style={{ marginTop: "30px", textAlign: "right" }}
>
Reps(x)
</Paragraph>
</Flex>
</TableCell>
<TableCell>
<Flex justifyContent={"center"}>1</Flex>
<TextInput
value={exercise.reps[0]}
data-index={index}
onChange={onChanged}
></TextInput>
</TableCell>
<TableCell>
<Flex justifyContent={"center"}>2</Flex>
<TextInput
value={exercise.reps[1]}
data-index={index}
onChange={onChanged}
></TextInput>
</TableCell>
<TableCell>
<Flex justifyContent={"center"}>3</Flex>
<TextInput
value={exercise.reps[2]}
data-index={index}
onChange={onChanged}
></TextInput>
</TableCell>
<TableCell>
<Flex justifyContent={"center"}>4</Flex>
<TextInput
value={exercise.reps[3]}
data-index={index}
onChange={onChanged}
></TextInput>
</TableCell>
<TableCell>
<Flex justifyContent={"center"}>5</Flex>
<TextInput
value={exercise.reps[4]}
data-index={index}
onChange={onChanged}
></TextInput>
</TableCell>
<TableCell>
<SectionHeading element="h5">Intensity</SectionHeading>
<Flex marginRight={"spacing2Xl"} alignItems="center">
<RadioButtonField
labelText="Maximum"
name="someOption1"
// checked={activeOption === "yes"}
value="yes"
// onChange={(e) => {
// setActiveOption(
// (e.target as HTMLInputElement).value
// );
// }}
id="termsCheckbox"
/>
</Flex>
<Flex alignItems="center">
<RadioButton
id="Checkbox"
labelText="some label text"
name="some-name"
/>
<TextInput placeholder="%1RM" />
</Flex>
</TableCell>
<TableCell>
<EditorToolbarButton
icon="Delete"
data-index={index}
onClick={onDeleteButtonClicked}
></EditorToolbarButton>
</TableCell>
</TableRow>
</>
);
})}
</TableBody>
</Table>
</div>
<div style={{ marginTop: "10px", marginBottom: "10px" }}>
<Button icon="Plus" buttonType="naked" onClick={onAddButtonClicked}>
Add
</Button>
</div>
</section>
);
};
export default ExercisesList;
Upvotes: 3
Views: 447
Reputation: 1450
https://snack.expo.io/@jsfit/text-inputs
exerciseIndex is the same for every rep which causes replacing in value
just pass the rep index as well
const onChanged = (e) => {
const exerciseIndex = e.target.dataset.index;
const repIndex = e.target.dataset.repindex;
const updatedExercises = [...exercises];
if(repIndex>-1){
updatedExercises[exerciseIndex].reps[repIndex] = e.target.value;
} else {
updatedExercises[exerciseIndex].amount = e.target.value;
}
setExercises(updatedExercises);
;
<TextInput
value={exercise.amount}
data-index={index}
data-repindex={-1}
onChange={onChanged}>
</TextInput>
<TextInput
value={exercise.reps[4]}
data-index={index}
data-repindex={4}
onChange={onChanged}>
</TextInput>
Upvotes: 1