3

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

enter image description here

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;

1 Answer 1

1

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>
Sign up to request clarification or add additional context in comments.

4 Comments

Ok made the change but it doesn't seem to be passing that through?
@DavidRiches a working example is attached with the answer hope that works for you.
The example does not run for me.
I had to change some bits but I expanded on your answer, thankyou.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.