1

I am struggling with some React functionality. My goal is to create a form where a day template can be added (for context - like a training club can make up a template of trainings for the day and then schedule them regularly). For that I wanted to add a button which onClick will create a smaller block with 2 form fields - time and training info. And I need user to add several of those, as much as they want.

The thing is, while I understand a bit how react works, it seems to me I am just banging my head against the wall with this, as one thing is to render a component, but another to generate a bunch of same, completely new ones and connected to the form somehow, so I can send the data when clicking submit button.

Here is repository with this component: https://github.com/badgerwannabe/spacefitness-test-client

Here is path to this component spacefitness-test-client/src/components/template-components/addTemplateForm.js

Here below how it looks rendered

How it looks at the moment

UPDATE 1 here is the full component here:

import React, {useState}  from "react";
import {useMutation } from "@apollo/client";
import {useForm} from '../../utils/hooks'
import { Button, Form  } from "semantic-ui-react";

import {FETCH_TEMPLATES_QUERY, FETCH_TRAININGS_QUERY,ADD_TEMPLATES_MUTATION} from '../../utils/graphql'

//hook for form functioning
function AddTemplateForm (props){
   
    const {values, onChange, onSubmit} = useForm(createDayCallback,{
        date:'', dayTrainings:[{
          time:'testing time', training:"60e9e7580a6b113b2486113a"
        },{
          time:'testing2 time2', training:"61ec6a6d0f94870016f419bd"
        }
        ]
    });

//apollo hook to send data through GraphQL    
const [createDay, {error}] = useMutation(ADD_TEMPLATES_MUTATION, {
    errorPolicy: 'all',
    variables:values, 
    update(proxy, result){
        const data = proxy.readQuery({ 
            query:FETCH_TEMPLATES_QUERY,
        });
        
        proxy.writeQuery({query:FETCH_TEMPLATES_QUERY,
        data:{
            getDays: [result.data.createDay, ...data.getDays]
        }})
       
        props.history.push('/templates')
    },},
    {});

    function createDayCallback(){
        createDay();
    }
    
  //little component I want to dynamically add each time people press a button  
  function addDayTraining(){

    const addDayTraining = (
      <>

      <Form.Field>
            <Form.Input
               placeholder="time"
               name="time"
               onChange={()=>{
                 console.log("time")
               }}
               values={values.time}
               error={error ? true : false}
               />
            <Form.Input
               placeholder="training"
               name="training"
               onChange={()=>{
                 console.log("training")
               }}
               values={values.training}
               error={error ? true : false}
               />
  </Form.Field>



      </>
    )
    return addDayTraining
  }
    
//Form component itself
    const AddTemplateForm = (
        <>
        <Form onSubmit={onSubmit}>
        <h2>Add a template :</h2>
        <Form.Field>
            <Form.Input
               placeholder="date"
               name="date"
               onChange={onChange}
               values={values.date}
               error={error ? true : false}
               />
  </Form.Field>
                 <Form.Field> 
                 <Button type="button" onClick={
                   addDayTraining
                 }>Add training</Button>
                 
                </Form.Field>

               <Button type ="submit" color="teal">Submit</Button>
      

        
    </Form>
    {error && (
    <div className="ui error message" style={{marginBottom:20}}>
        <li>{error.graphQLErrors[0].message}</li>
    </div>
)}
  
    </>
    )
    return AddTemplateForm
    }
export default AddTemplateForm;

2
  • Is this something you've tried already on your own? Can you update your question to include a minimal, complete, and reproducible code example? Commented Jan 29, 2022 at 8:22
  • Hi @DrewReese, thank you for your comment, yes, I tried but everything just does not feel right and I feel stuck with this. It seems to me am missing some crucial point. I will update with minimal, complete and reproducible code example Commented Jan 29, 2022 at 8:34

1 Answer 1

1

Can you just set up a function on the submit button which pushes an object with {time: new Date(), trainingInfo: ""} and push that object into an existing array of training objects? (obviously starting empty)

You could then map those objects into a component and when the component is updated (i.e. when the user adds a time and training details text) use a callback function to update the values in the array at the index of that object.

export default function yourIndexPage({yourprops}) {
    const [trainingObjects, setTrainingObjects] = useState([]);

    function addTraining(){
        const newTrainingObject =  {
                time: new Date(), //assuming you want it to default to todays date 
                trainingInfo: "your placeholder text"
            };
        setTrainingObjects([...trainingObjects, newTrainingObject]);
    }

    //I am assuming your training object will be a list item here so wrapped in <ul>
    return(
        <div>
            <div className='your list of training things'> (might need to set style as flex and add some padding etc..)
                {trainingObjects.length === 0 ? <div/> : trainingObjects.map((trainingObject, index) => (
                    <YourTrainingObjectComponent trainingObject={trainingObject} trainingItemIndex={index} key={index}/>
                ))}
            </div>
            <Button onClick={() => {addTraining}} />
        </div>
    )
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you man! That is what I needed and most important you lead me onto a right path, I was completely lost, don't know why, as I thought I got this React concept a while ago.
No problem! It only clicked for me a few months ago myself

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.