BadgerWannaBe
BadgerWannaBe

Reputation: 37

How to generate a component in React Form onClick

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;

Upvotes: 1

Views: 1036

Answers (1)

John Shanks
John Shanks

Reputation: 185

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>
    )
}

Upvotes: 1

Related Questions