Is there a way to handle input hidden value in onSubmit? - reactjs

I'm creating a todo app and I'm thinking of sending the id of the todo I want to delete using the post method to delete it. I'm currently using <form action="localhost" method="delete">, but I'd like to do something a little more complicated, so I'm trying to pass the id to the OnSubmit handler. is there a way to use the id in OnSubmit? Is there any way to use id in OnSubmit?
Implemented code
import React, {useState, useEffect} from "react";
import axios from "axios";
interface Todo {
id: number,
text: string,
}
const ShowContent = () => {
const [todoes, setTodoes] = useState<Todo[]>([]);
useEffect(() => {
axios.get<Todo[]>("http://localhost:8888")
.then(res => {
setTodoes(res.data)
})
.catch(_ => alert("useeffect error"))
}, [])
return (
<div>
<h1>Todo App</h1>
{todoes.map(todo =>
<div key={todo.id}>
<div>id: {todo.id}, text: {todo.text}</div>
<form action="localhost:8888" method="post">
<input type="hidden" name="id" value={todo.id}></input>
<button>Delete</button>
</form>
</div>
)}
<div>
<form action="localhost:8888" method="post">
<input type="text"></input>
<button>Submit</button>
</form>
</div>
</div>
);
}
What I want to do
import React, {useState, useEffect} from "react";
import axios from "axios";
interface Todo {
id: number,
text: string,
}
const ShowContent = () => {
const [todoes, setTodoes] = useState<Todo[]>([]);
useEffect(() => {
axios.get<Todo[]>("http://localhost:8888")
.then(res => {
setTodoes(res.data)
})
.catch(_ => alert("useeffect error"))
}, [])
const handleOnSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// I want to get the id here.
}
return (
<div>
<h1>Todo App</h1>
{todoes.map(todo =>
<div key={todo.id}>
<div>id: {todo.id}, text: {todo.text}</div>
<form onSubmit={handleOnSubmit}>
<input type="hidden" name="id" value={todo.id}></input>
<button>submit</button>
</form>
</div>
)}
</div>
);
}
export default ShowContent;

It is possible to get the id from your hidden input through the event using e.target either with FormData or document.querySelector, but there are Typsecript issues with this.
You already have access to the todo in the loop where you create the form, so my recommendation is that you create a function which already knows the id.
You can change your handler to a curried function like this:
const handleOnSubmit = (id: number) => (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log(`submitted todo ${id}`);
}
And use it like this:
<form onSubmit={handleOnSubmit(todo.id)}>

Related

How to handle multiple select options submittion in react js?

I want to submit a form into mongoDB using nodejs API & reactJs. With the exception of the multiple select option, everything is operating as it should be.
Being new to react, I have no idea how to handle the multi select option's onChange method.
Here is what I've tried:
import React, { useState, useRef } from "react";
import { useForm } from "react-hook-form";
import { v4 as uuidv4 } from 'uuid';
import axios from "axios";
import Select from 'react-select';
export default function EventForm(props) {
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm();
const form = useRef();
const [loading, setLoading] = useState(false);
const [info, setInfo] = useState("");
const [analysis, setAnalysis] = useState("Undefined");
const [relatedEvent, setRelatedEvent] = useState([]);
const handleInfoChange = (e) => {
setInfo(e.target.value)
}
const handleAnalysisChange = (e) => {
setAnalysis(e.target.value)
}
const handleRelatedEvents = (e) => {
setRelatedEvent(e.target.value)
}
const relatedEventsData = props.data.map(opt => ({ label: opt.info, value: opt._id }));
const onSubmit = async () => {
setLoading(true);
const MySwal = withReactContent(Swal);
const eventData = {
UUID: uuidv4(),
info: info,
analysis: analysis,
relatedEvent: relatedEvent,
}
axios
.post(`${process.env.REACT_APP_PROXY}/api/events`, eventData)
.then((res) => {
console.log(res);
setLoading(false);
MySwal.fire(
"Success!",
"A new event has been saved successfully",
"success"
);
})
.catch((error) => {
console.log(error);
});
};
return (
<div className="panel-body">
<Form
ref={form}
onSubmit={handleSubmit(onSubmit)}
className="form-horizontal"
>
<div className="row">
<div className="col-lg-6">
<div className="mb-3">
<Form.Label>Info</Form.Label>
<Form.Control
type="text"
placeholder="Enter info..."
{...register("info", { required: true })}
value={info}
onChange={handleInfoChange}
/>
{errors.info && (
<ul className="parsley-errors-list filled" id="parsley-id-7" aria-hidden="false">
<li className="parsley-required">This value is required.</li>
</ul>
)}
</div>
</div>
<div className="col-lg-6">
<div className="mb-3">
<Form.Label>Related events</Form.Label>
<Select
options={relatedEventsData}
value={relatedEvent}
isMulti
onChange={handleRelatedEvents}
/>
</div>
</div>
<div className="col-lg-12">
<Button variant="primary" type="submit">
{loading ? "Saving..." : "Save"}
</Button>
</div>
</div>
</Form>
</div>
);
}
Could you please guide me how to make it work!
Thank you
you can make use of Select onChange event handler which passes the selected options as an array as argument ..
from that you can map over it to get the values as required
something as below:
const handleChange = (opts) => {
const selectedValues = opts.map((opt) => opt.value);
setSelectedValues(selectedValues);
};
Please check the working sample for better clarity 😉 -

How to create a label and input dynamically using ReactJS

I'm working on creating a dynamic input form, where I want to click on a button and get a pop-up asking for label name and input type(Eg: number or text). Here is a mock-up of what I want to create. I should be able to even remove these newly created label and input.
Once this is entered, it should create a new label and input form as below:
Any help will be greatly appreciated.
Looks like I'm doing someone else's work but...)))
A quick example so you know which way to go:
YourMainComponent.tsx:
import React, { useState } from "react";
import { DynamicForm } from "./dynamic-form";
export const Fields = () => {
const [getFields, setFields] = useState([]);
const addField = (field) => {
setFields((prevState) => [...prevState, field]);
};
return (
<>
<DynamicForm onSubmit={addField} />
{getFields &&
getFields.map((field, index) => (
<fieldset key={index}>
<label>{field.label}</label>
<input type={field.type} />
</fieldset>
))}
</>
);
};
YourDynamicFieldCreateComponent:
import React, { useState } from "react";
export const DynamicForm = ({ onSubmit }) => {
const [getField, setField] = useState({});
const formSubmit = (e) => {
e.preventDefault();
if (Object.keys(getField).length > 0) {
onSubmit(getField);
setField({});
}
};
const onFieldChanged = (e) => {
if (e.target.id === "label-field") {
setField((prevState) => ({
...prevState,
label: e.target.value
}));
} else if (e.target.id === "type-field") {
setField((prevState) => ({
...prevState,
type: e.target.value
}));
}
};
return (
<form onSubmit={formSubmit}>
<fieldset>
<label htmlFor="label-field">Your label </label>
<input
type="text"
id="label-field"
name="label-field"
onChange={onFieldChanged}
/>
</fieldset>
<fieldset>
<label htmlFor="type-field">Your type of field </label>
<input
type="text"
id="type-field"
name="type-field"
onChange={onFieldChanged}
/>
</fieldset>
<button>Add more</button>
</form>
);
};
Need add conditions and modals and other...
This is not production code, use this only for learning

How to update the parent / list component from the child / detail component in ReactJS?

I am beginner and practicing on Library Management System in react. So I have components named BookDetails.js, BookList.js. BookDetails contains the form for entering Title and Description. So How can I pass the data entered from BookDetails to BookList and to dispaly from App.
import React, { useState } from 'react'
import BookList from './BookList'
const BookDetails = (props) => {
const [bookdetails, setbookDetails] = useState('')
const [desc, setDesc] = useState('')
const titleChangehandler = (e) => {
setbookDetails(e.target.value)
}
const descriptionChangehandler = (e) => {
setDesc(e.target.value)
}
const submitHandler = (e) => {
e.preventDefault()
return (
<div className='bookdetails'>
<form className='form_bookdetails' onSubmit={submitHandler}>
<div>
<label>Enter Title:</label>
<input type='text' value={bookdetails} onChange={titleChangehandler}></input>
</div>
<div>
<label>Enter Description:</label>
<input type='text' value={desc} onChange={descriptionChangehandler}></input>
</div>
<div>
<button type='submit'>Add Details</button>
</div>
</form>
</div>
)
}
}
export default BookDetails
BookList.js
import React from 'react'
import './BookList.css'
import BookDetails from './BookDetails'
const BookList = () => {
return (
<div className="booklist">
<header>BookList</header>
<BookDetails />
</div>
)
}
export default BookList
You need to use props. BookList state will have an update function that it will pass to the BookDetail via props. Example (CodeSandbox) with Todo with title & description.
BookDetail will invoke this method on every save which then would update the original list.
TodoList.js
export default function TodoList() {
const [todo, setTodo] = React.useState(null);
const [todoList, setTodoList] = React.useState([]);
React.useEffect(() => {
getTodos();
}, []);
function getTodos() {
console.log("===> fetch all todos!!");
fetchTodos().then((todos) => {
setTodoList(todos);
});
}
function editTodo(todo) {
console.log("===> set todo => ", todo);
setTodo(todo);
}
function handleUpdate(updatedTodo) {
// update Todo
const updatedTodos = todoList.map((el) =>
el.id === updatedTodo.id ? updatedTodo : el
);
setTodoList(updatedTodos);
setTodo(null);
}
return (
<div>
<ul>
{todoList.map((item) => (
<li key={item.id}>
{item.title}, {item.description}
<button onClick={() => editTodo(item)}>edit</button>
</li>
))}
</ul>
{todo && <TodoDetail todo={todo} updateTodo={handleUpdate} />}
</div>
);
}
TodoDetail.js
import React from "react";
export default function TodoDetail(props) {
const [todo, setTodo] = React.useState(props.todo);
console.log("todo =>", todo);
function handleChange(key, value) {
console.log("===> todo changed!");
setTodo({
...todo,
[key]: value
});
}
function handleSubmit() {
// api PUT on todo
console.log("===> todo edit submit!!");
props.updateTodo(todo);
}
return (
<div>
<form onSubmit={handleSubmit}>
<label htmlFor="title">
<input
value={todo.title}
onChange={(e) => handleChange("title", e.target.value)}
/>
<input
value={todo.description}
onChange={(e) => handleChange("description", e.target.value)}
/>
</label>
<button type="submit">submit</button>
</form>
</div>
);
}
You can store the list of books in your BookList component like
const [bookList, setBookList] = useState([])
This way your BookList component has access to the books. You can then create a function to add books to the list
function addBook(book) {
setBookList([...bookList, book])
}
Then pass the addBook() function to the BookDetails component to use it on submit.
<BookDetails addBook={addBook}
Now BookDetails can access the function as a prop
props.addBook("pass new book here")

react js myfn is not a function when called from a button

I've just started learning about react js and this is my first react js app. I'm using api to fetch the data. so far it works, but now I want to add a search keyword to the function that is acquired from a search bar component.
here's my code:
SearchBar.js
const SearchBar = ({ getUsers }) => {
return (
<div className="is-flex flex-align-items-center mb-3">
<input type="text" id="query" className="input search-input" placeholder="search keyword"/>
<Button className="search-btn ps-3 pe-3"
onClick={() => getUsers(document.querySelector('#query').value)}>
<FontAwesomeIcon icon={faMagnifyingGlass} />
</Button>
</div>
);
};
MasterUser.js
import { useState, useEffect } from "react";
import SearchBar from "./SearchBar";
const MasterUser = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
getUsers();
}, []);
const getUsers = async (query='') => {
console.log('get users', query);
try {
let myurl = 'http://localhost:8080/users';
const response = await fetch(myurl);
const data = await response.json();
setUsers(data);
setIsLoading(false);
} catch (e) {
console.log(e.getMessage());
}
};
return (
<div>
<SearchBar onClick={getUsers}/>
</div>
);
};
when the app loads, the console log says get users <empty string> and it returns all the users as expected, but when I clicked on the search button (magnifyingGlass) it gives an error Uncaught TypeError: getUsers is not a function.
any help is appreciated..
<SearchBar onClick={getUsers}/>
You have named the prop onClick not getUsers. That's why you get that error.
Yeah, accessing dom element value using selectors (e.g. document.querySelector('#query').value) is also not typical react. Read about controlled form elements (save form element value in state).
Make your searchBar component more reactive like so
const SearchBar = ({ getUsers }) => {
const [searchValue,setSearchValue]=useState('');
return (
<div className="is-flex flex-align-items-center mb-3">
<input type="text" id="query" className="input search-input" placeholder="search keyword" value={searchValue} onChange={(e)=>setSearchValue(e.target.value)}/>
<Button className="search-btn ps-3 pe-3"
onClick={() => getUsers(searchValue)}>
<FontAwesomeIcon icon={faMagnifyingGlass} />
</Button>
</div>
);
};

Why is the API response not being rendered by useState?

I am trying to render data fetched from an API using axios but nothing renders on screen. Note that data is actually available as indicated on the console log. Here is the code and what I have tried.
import React, { useState, useEffect } from "react";
import axios from "axios";
function Test() {
const [movie, setMovie] = useState([]);
const [query, setQuery] = useState("pulp fiction");
const [queryFromButtonClick, setQueryFromButtonClick] = useState(
"pulp fiction"
);
const handleClick = () => {
setQueryFromButtonClick(query);
};
useEffect(() => {
axios
.get(`http://www.omdbapi.com/?apikey=fd010aa6&s=${queryFromButtonClick}`)
.then(({ data }) => {
console.log(data);
setMovie(data.Search);
});
}, [queryFromButtonClick]);
return (
<div>
<input
type="text"
value={query}
onChange={(e) => {
setQuery(e.target.value);
}}
/>
<button onClick={handleClick}>Fetch movies</button>
<div>{movie.Title}</div>
</div>
);
}
export default Test;
Why are the search query results not being rendered on screen and how can I go on about that?
Movie is defined as an array and apparently data.Search is also an array.
You need to iterate over movie array to get the data about each movie.
Like this:
return (
<div>
<input
type="text"
value={query}
onChange={(e) => {
setQuery(e.target.value);
}}
/>
<button onClick={handleClick}>Fetch movies</button>
<div>{movie.map((el)=>el.Title)}</div>
</div>
);

Resources