1

I'm trying to have the user input multiple "themes" via a form input bar so that I can add it to the database. The schema model I have created for the object has the "theme" as an array so that part's done. I'm wondering if there's a way to add multiple input values to the same state variable theme in the code down below.

Here is what my code looks like:

import { useState } from "react";

const ProjectAdminForm = () => {
    const [sdg, setSDG] = useState('')
    const [goal, setGoal] = useState('')
    const [orginization, setOrginization] = useState('')
    const [source, setSource] = useState('')
    const [location, setLocation] = useState('')
    const [published, setPublished] = useState('')
    const [website_url, setWebsiteURL] = useState('')
    const [assignment_type, setAssignmentType] = useState('')
    const [theme, setTheme] = useState('')
    const [sharepoint_link, setSharepointLink] = useState('')
    const [statement, setStatement] = useState('')
    const [error, setError] = useState(null)

    const handleSubmit = async (e) => {
        e.preventDefault() // Prevents refresh of page from happening
        console.log('button clicked')
        const project = {sdg, goal, orginization, source, location, published, website_url, assignment_type, theme, sharepoint_link, statement}
        console.log(project)                
        // Sending form response to backend
        const response = await fetch('/api/projects', {
            method: 'POST',
            body: JSON.stringify(project),
            headers: {
                'Content-Type': 'application/json'
            }
        })
        const json = await response.json
        

        // Checking for error
        if (!response.ok) {
            setError(json.error)
        }
        if (response.ok) {
            // Reset form inputs back to empty string
            setSDG('')
            setGoal('')
            setOrginization('')
            setSource('')
            setLocation('')
            setPublished('')
            setWebsiteURL('')
            setAssignmentType('')
            setTheme('')
            setSharepointLink('')
            setStatement('')
            
            setError(null)
            console.log('new project added', json)
        }
    }

    return (
        <form className="create" onSubmit={handleSubmit}>
            <h3>Add a New Project</h3>

            <label>SDG (Num + Name):</label>
            <input 
                type="text"
                placeholder="e.g. SDG 2: Zero Hunger"
                onChange={(e) => setSDG(e.target.value)}
                value={sdg}
            />

            <label>Goal:</label>
            <input 
                type="text"
                onChange={(e) => setGoal(e.target.value)}
                value={goal}
            />

            <label>Orginization:</label>
            <input 
                type="text"
                onChange={(e) => setOrginization(e.target.value)}
                value={orginization}
            />

            <label>Source:</label>
            <input 
                type="text"
                onChange={(e) => setSource(e.target.value)}
                value={source}
            />

            <label>Location:</label>
            <input 
                type="text"
                onChange={(e) => setLocation(e.target.value)}
                value={location}
            />

            <label>Published:</label>
            <input 
                type="text"
                onChange={(e) => setPublished(e.target.value)}
                value={published}
            />

            <label>Website URL:</label>
            <input 
                type="text"
                onChange={(e) => setWebsiteURL(e.target.value)}
                value={website_url}
            />

            <label>Assignment Type:</label>
            <input 
                type="text"
                onChange={(e) => setAssignmentType(e.target.value)}
                value={assignment_type}
            />

            <label>Theme:</label>
            <input 
                type="text"
                onChange={(e) => setTheme(e.target.value)}
                value={theme}
            />

            <label>Sharepoint Link:</label>
            <input 
                type="text"
                onChange={(e) => setSharepointLink(e.target.value)}
                value={sharepoint_link}
            />

            <label>Statement:</label>
            <input 
                type="text"
                onChange={(e) => setStatement(e.target.value)}
                value={statement}
            />

            <button>Add Project</button>
            {error && <div className="error">{error}</div>}
        </form>
    )
}

export default ProjectAdminForm

Specifically for the theme input:

                <label>Theme:</label>
                <input 
                    type="text"
                    onChange={(e) => setTheme(e.target.value)}
                    value={theme}
                />

, how can I have multiple inputs that link to the same theme state which holds them all as an array and then gets passed on to the backend via handleSubmit? Say a user wants to enter "magic", "joy", and "fun" as the themes, how could I make it so that all 3 of those get stored in the theme state variable via the input form?

3 Answers 3

2

As array:

//initialise an empty array as the default state for adding themes
const [themes, setThemes] = useState([]);
//create an array to hold your theme names
  const available_themes = ['magic', 'joy', 'fun', 'more'];

//create a function for adding themes to your state array
  const addTheme = (name) =>{
    //if the theme to be added does not exists in the array
    if(!themes.includes(name)){
      //make a copy (...) of the current themes, and add your new theme name to a new array
      setThemes([...themes, name])
    }

  }

//create a function for removing items from the array
  const removeTheme = (name) =>{
    //get the index (position) of the theme name in the current state array
    const index = themes.indexOf(name);
    //if the item exists in the themse array(has an index, is not -1)
    if(index !== -1) {
      //copy the current array to a tempory data store
      let temp_themes = [...themes];
      //remove the item from the array using its index
      temp_themes.splice(index, 1);
      //now save the new array to your state variable of themes
      setThemes(temp_themes);
    }

  }

  //for each available theme name create a check box
  const themeselector = available_themes.map((name)=>{
        //we check if the check box needs to be set to checked, i.e. selected
        let checked = false;
        //if the current theme is in the theme array it should be selected
        if(themes.includes(name)){
           checked = true;
        }

        // we add the checked=checked property {checked: 'checked'} to the check box if the list item should be checked using {...(checked ? {checked: 'checked'}: {})} where (boolean ? on true : else on false )
        
        //we get the ev.target.checked variable to see if the check box has been selected or deselected. We either addTheme, or removeTheme based upon the value of teh variable.

        return <div><input type="checkbox" {...(checked ? {checked: 'checked'}: {})}  value={name} onClick={(ev)=>{ if(ev.target.checked) {  addTheme(name)  } else { removeTheme(name)} } } /> {name}</div>;
  });

As object:

const [themes, setThemes] = useState({});
  const available_themes = ['magic', 'joy', 'fun', 'more'];

  const addTheme = (name) =>{
       if(typeof themes[name] == 'undefined') {
         let temp_themes = {...themes};
         temp_themes[name] = name;
         setThemes(temp_themes);
       }

  }

  const removeTheme = (name) =>{
    if(typeof themes[name] !== 'undefined') {
      let temp_themes = {...themes};
      delete temp_themes[name];
      setThemes(temp_themes);
    }

  }


  const themeselector = available_themes.map((name)=>{
        let checked = false;
        if(typeof themes[name] !== 'undefined'){
           checked = true;
        }

        return <div><input type="checkbox" {...(checked ? {checked: 'checked'}: {})}  value={name} onClick={(ev)=>{ if(ev.target.checked) {  addTheme(name)  } else { removeTheme(name)} } } /> {name}</div>;
  });
<label>Select Themes</label>
{themeselector}

Sign up to request clarification or add additional context in comments.

3 Comments

I was wondering if you could explain the themeselector part of the array code for me, sorry I'm new to react and want to recreate your code my way! Thank you so much though!
Let me know what type of selector you want to use, and what you would like to change, I can then give you some direction.
Have added comments to the code I hope it helps with understanding it.
0

You could do something like this, I guess:

const [theme, setTheme] = useState([''])

And then define a function addTheme that would call setTheme and add a string if it's not already present in the array.

function addTheme(newTheme){
  if(!theme.includes(newTheme){
    setTheme([...theme, newTheme])
  }
}

Comments

0

If you want to use a single text input, one could just create a new array with the values:

const [themes, setThemes] = useState([]);
const [themeText, setThemeText] = useState("");

onSubmit(e) {
  e.preventDefault();

  setThemes(themeText.split(" "));
}
<label>Theme:</label>
<input 
    type="text"
    onChange={(e) => setThemeText(e.target.value)}
    value={themeText}
/>

Comments

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.