State React JS Array Issue - reactjs

I am trying to edit user input but the click event point to the input at array 0. i wanted to be able to render only the input to be edited.
The full project is available on sandbox via the link below. I am new to react developing and struggling with state. Can someone help, please?
To see what i mean by the above, please enter some input and click add 2 different input then edit the car. Only the inputs 0 is rendered.
https://codesandbox.io/s/eloquent-feather-gc88n?file=/src/header/header.js
Thank Leo
import React, { useState } from "react";
const EditSkillsForm = ({
handleUpdateInput,
inputs,
handleCancelClick,
//setCurrentSkill,
}) => {
const [currentSkill, setCurrentSkill] = useState({});
const [isEditing, setIsEditing] = useState(true);
// const [ onSubmitEditing, SetOnSubmitEditing ] = useState("")
function handleEditInputChange(e) {
setCurrentSkill(e.target.value);
}
handleCancelClick = (e) => {
setIsEditing(false);
console.log("Cancel edit");
//return {...prevState, isEditing : isEditing }
};
return (
<>
{isEditing ? (
<div>
<h4>Edit Skill</h4>
<input
className="mb-2"
size="lg"
onChange={handleEditInputChange}
type="text"
name="Update skill"
placeholder="Update skill"
value={[inputs[0]]}
/>
<button className="btn btn-primary mx-2" onClick={handleUpdateInput}>
Update
</button>
<button onClick={() => handleCancelClick()}>Cancel</button>
</div>
) : null}
</>
);
};
export default EditSkillsForm;

If you are editing 1 element at a time you shouldn't pass all the inputs.
Only pass the object you wanna show/permit to edit.
const EditSkillsForm = ({
handleUpdateInput,
input,
handleCancelClick,
//setCurrentSkill,
})
...
<input
className="mb-2"
size="lg"
onChange={handleEditInputChange}
type="text"
name="Update skill"
placeholder="Update skill"
value={input}
/>

Related

empty data instead of data from the array when changing the data in the input react js

I have a simple todo list that consists of multiple inputs.
I made the editing functionality and now everything works as it should, but only once. When I change the input data for the first time, it saves everything to an array with the correct data.
And when I want to do it a second time, then in order to save this data, three inputs must be changed.
I want that even when changing one input, the data is saved in an array (data that has not been changed is overwritten).
Stackblitz code
App.js
function App(props) {
const [tasks, setTasks] = useState(props.tasks);
function editTask(id, newName, newTranslate, newNote) {
const editedTaskList = tasks.map((task) => {
if (id === task.id) {
return { ...task, name: newName , translate: newTranslate , note: newNote };
}
return task;
});
setTasks(editedTaskList);
}
const taskList = tasks
.map((task) => (
<Todo
id={task.id}
name={task.name}
translate={task.translate}
note={task.note}
completed={task.completed}
key={task.id}
editTask={editTask}
tasks={tasks}
/>
));
return (
<div className="todoapp stack-large">
<ul
className="todo-list stack-large stack-exception"
aria-labelledby="list-heading">
{taskList}
</ul>
</div>
);
}
export default App;
I did a check and added the save button onClick which outputs the data to the console. It gives the data correctly the first time, and if the same item in the todo is changed the second time, it gives an empty space instead of the data that has not been changed.
Todo.js
export default function Todo({name, translate, note, editTask, id, tasks}) {
const [isEditing, setEditing] = useState(false);
const [newName, setNewName] = useState(name);
const [newTranslate, setNewTranslate] = useState(translate);
const [newNote, setNewNote] = useState(note);
function handleChange(e) {
setNewName(e.target.value)
}
function handleChangeTranslate(e) {
setNewTranslate(e.target.value);
}
function handleChangeNote(e) {
setNewNote(e.target.value)
}
function handleSubmit(e) {
e.preventDefault();
if (!newName.trim()|| !newTranslate.trim() || !newNote.trim()) {
return;
}
editTask(id, newName,newTranslate,newNote);
setNewName("");
setNewTranslate("");
setNewNote("");
setEditing(false);
}
const editingTemplate = (
<form className="stack-small" onSubmit={handleSubmit}>
<div className="form-group">
<input
id={id}
className="todo-text"
type="text"
autoComplete='off'
defaultValue={newName || name}
onChange={handleChange}
placeholder="write word"
/>
<input
id={id}
className="todo-text"
type="text"
autoComplete='off'
defaultValue={newTranslate || translate}
onChange={handleChangeTranslate}
placeholder="write translate"
/>
<input
id={id}
className="todo-text"
type="text"
autoComplete='off'
defaultValue={newNote || note}
onChange={handleChangeNote}
placeholder="write note"
/>
</div>
<div className="btn-group">
<button
type="button"
className="btn todo-cancel"
onClick={() => setEditing(false)}
>
Cancel
</button>
<button type="submit" className="btn btn__primary todo-edit" onClick={()=>console.log(newName, newTranslate, newNote)}>
Save
</button>
</div>
</form>
);
const viewTemplate = (
<div className="stack-small">
<div className="c-cb">
<label className="todo-label" htmlFor={id}>
{name}
</label>
<label className="todo-label" htmlFor={id}>
{translate}
</label>
<label className="todo-label" htmlFor={id}>
{note}
</label>
</div>
<div className="btn-group">
<button
type="button"
className="btn"
onClick={() => setEditing(true)}
>
Edit <span className="visually-hidden">{name}</span>
</button>
</div>
</div>
);
return <li className="todo">{isEditing ? editingTemplate : viewTemplate}</li>;
}
Since you want to keep those preview state which was not edit and still print out those state with the one you edit, you can just remove all the "reset state '' you put, since all your initial state from useState already had a value and is not an empty string "" like this
function handleSubmit(e) {
e.preventDefault();
if (!newName.trim()|| !newTranslate.trim() || !newNote.trim()) {
return;
}
editTask(id, newName,newTranslate,newNote);
setEditing(false);
}

Get the clicked object and fill the inputs in ReactJS

What I want to achieve is to be able to get all the new data on the next object that is added, also be able to click on the printed divs and get that current object to edit. I've built something, but the key logic is missing.
Problems:
Show current input fields
Be able to switch to the div (objects) and get the values in the input so I can edit
import { useState, useEffect } from 'react';
export default function AddQuiz() {
const [current, setCurrent] = useState(1);
const [questions, setQuestions] = useState([]);
function add_question() {
const dumb = {
id: `${Math.floor(100000 + Math.random() * 900000)}`,
question: `${Math.random().toString(36).substr(2, 5)}`,
anwser1: `${Math.random().toString(36).substr(2, 5)}`,
anwser2: `${Math.random().toString(36).substr(2, 5)}`,
anwser3: `${Math.random().toString(36).substr(2, 5)}`,
anwser4: `${Math.random().toString(36).substr(2, 5)}`,
};
setQuestions([...questions, dumb]);
}
return (
<>
<pre>
{' '}
{questions.map((item) => (
<div>
question: {item.question} anwser1: {item.anwser1} anwser2: {item.anwser2} anwser3: {item.anwser3} anwser4:{' '}
{item.anwser4}
</div>
))}{' '}
</pre>
<button onClick={() => add_question()}>add dump question</button>
<br />
<br />
<hr />
{questions.length !== 0 ? (
<form>
<input type="text" value={questions[0].question} />
<input type="text" value={questions[0].anwser1} />
<input type="text" value={questions[0].anwser2} />
<input type="text" value={questions[0].anwser3} />
<input type="text" value={questions[0].anwser4} />
</form>
) : (
'please add some question'
)}
</>
);
}
You need to add onChange in your input field and use it properly.
Here I've created a codesandbox, that you're looking for. https://codesandbox.io/s/redux-shop-cart-forked-z891d?file=/src/App.js
how about this:
const [que1, setQue1] = useState("");
function add_question() {
const dumb = {
question: que1 ? que1 : Math.random().toString(36).substr(2, 5),
};
setQuestions([...questions, dumb]);
}
<input
type="text"
onChange={(e) => setQue1(e.target.value)}
defaultValue={questions[0].question}
/>
try:
example

Todo list Reverse state to false on click onclick

I am trying to reverse a state to true or false when user is clicking the cancel button.
The full project is available on sandbox via the link below. I am new to react developing and struggling with state. Can someone help, please?
To see what i mean by the above, please enter some input and click add
https://codesandbox.io/s/eloquent-feather-gc88n?file=/src/header/header.js
Thank Leo
Update your handleCancelClick function to this:
handleCancelClick = (e) => {
setIsEditing((prevState) => !prevState)
console.log('Cancel edit', isEditing)
}
Few more amends that you might need:
In skillist.js:
<EditSkillsForm
inputs={inputs}
isEditing={isEditing}
setIsEditing={setISEditing}
onCancelClick={handleCancelClick}
onUpdateInput={handleUpdateInput}
onCurrentInput={currentInput}
/>
In editSkillsForm.js, we get isEditing and setIsEditing props also :
const EditSkillsForm = ({
handleUpdateInput,
inputs,
handleCancelClick,
setCurrentSkill,
isEditing,
setIsEditing
}) => {
Full file code (just in case):
editSkillsForm.js:
import React, { useState } from "react";
const EditSkillsForm = ({
handleUpdateInput,
inputs,
handleCancelClick,
setCurrentSkill,
isEditing,
setIsEditing
}) => {
//const [ currentSkill, setCurrentSkill ] = useState({});
// const [isEditing, setIsEditing] = useState(true);
// const [ onSubmitEditing, SetOnSubmitEditing ] = useState("")
function handleEditInputChange(e) {
setCurrentSkill(e.target.value);
}
handleCancelClick = (e) => {
setIsEditing(false);
console.log("Cancel edit", isEditing);
};
return (
<>
{isEditing ? (
<div>
<h4>Edit Skill</h4>
<input
className="mb-2"
size="lg"
onChange={handleEditInputChange}
type="text"
name="Update skill"
placeholder="Update skill"
value={inputs}
/>
<button className="btn btn-primary mx-2" onClick={handleUpdateInput}>
Update
</button>
<button onClick={() => handleCancelClick()}>Cancel</button>
</div>
) : null}
{/* <div>
<h4>Edit Skill</h4>
<input
className="mb-2"
size="lg"
onChange={handleEditInputChange}
type="text"
name="Update skill"
placeholder="Update skill"
value={inputs}
/>
</div> */}
{/* <input
className="mb-2"
size="lg"
onChange={handleEditInputChange}
type="text"
name="Update skill"
placeholder="Update skill"
value={inputs}
/> */}
{/* <button className="btn btn-primary mx-2">Update</button> */}
{/* <button onClick={() => handleCancelClick()}>Cancel</button> */}
</>
);
};
export default EditSkillsForm;

React - how to target value from a form with onClick

New to react and currently working on a project with a backend.
Everything functions correctly apart from targeting the value of user selection.
basically whenever a user enters a number the setId is saved properly to the const with no problems while using the onChange method.
this method would render my page every change on text.
I am trying to save the Id only when the user clicks the button. however,
event.target.value does not work with onClick.
I tried using event.currentTarget.value and this does not seem to work.
Code:
<form onSubmit={handleSubmit}>
<label>Company ID</label>
<input value={id} onChange={(e) => setId(e.target.value)} type="number" />
{/* <button value={id} type="button" onClick={(e) => setId(e.currentTarget.value)}>Search</button> */}
</form>
Handle Submit:
const handleSubmit = (e) => {
e.preventDefault();
console.log(id)
}
is there a way of doing this with onclick? since I wouldn't like my component to render on every typo and only once a user has clicked the button.
Componenet:
interface GetOneCompanyProps {
company: CompanyModel;
}
interface RouteParam {
id: any;
}
interface CompanyById extends RouteComponentProps<RouteParam> {
}
function GetOneCompany(): JSX.Element {
const [id, setId] = useState('4');
const [company, setCompany] = useState<any>('');
const handleSubmit = (e) => {
e.preventDefault();
console.log(id)
}
async function send() {
try {
const response = await axios.get<CompanyModel>(globals.adminUrls.getOneCompany + id)
store.dispatch(oneCompanyAction(response.data));
console.log(response);
const company = response.data;
setCompany(company)
} catch (err) {
notify.error(err);
}
}
useEffect(() => {
send();
}, [id]);
return (
<div className="getOneCompany">
<h1>hi </h1>
<form onSubmit={handleSubmit}>
<label>Company ID</label>
<input value={id} onChange={(e) => setId(e.target.value)} type="number" />
{/* <button value={id} type="button" onClick={(e) => setId(e.currentTarget.value)}>Search</button> */}
</form>
<div className="top">
</div>
<br/>
Company: {id}
<br/>
Client Type: {company.clientType}
<br/>
Company Name: {company.name}
<br/>
Email Adress: {company.email}
<br/>
</div>
);
}
export default GetOneCompany;
Hope I am clear on this.
Thanks.
You can turn your input from being a controlled input to an uncontrolled input, and make use of the useRef hook. Basically, remove most of your attributes from the input element, and grab the current value of the input form on click of the button. From there, you can do whatever you want with the input value.
const inputRef = useRef()
...other code
<form onSubmit={handleSubmit}>
<label>Company ID</label>
<input type="number" ref={inputRef} />
<button value={id} type="button" onClick={() => console.log(inputRef.current.value)}>Search</button>
</form>
...other code
I'm afraid to say that here onChange is mandatory as we also are interested in the value which we set by setId. onClick can't be used as we can't set the value in the input.
Hope I'm clear.
Thankyou!

In React with Formik how can I build a search bar that will detect input value to render the buttons?

New to Formik and React I've built a search component that I'm having issues with the passing of the input value and rendering the buttons based on input length.
Given the component:
const SearchForm = ({ index, store }) => {
const [input, setInput] = useState('')
const [disable, setDisable] = useState(true)
const [query, setQuery] = useState(null)
const results = useLunr(query, index, store)
const renderResult = results.length > 0 || query !== null ? true : false
useEffect(() => {
if (input.length >= 3) setDisable(false)
console.log('input detected', input)
}, [input])
const onReset = e => {
setInput('')
setDisable(true)
}
return (
<>
<Formik
initialValues={{ query: '' }}
onSubmit={(values, { setSubmitting }) => {
setInput('')
setDisable(true)
setQuery(values.query)
setSubmitting(false)
}}
>
<Form className="mb-5">
<div className="form-group has-feedback has-clear">
<Field
className="form-control"
name="query"
placeholder="Search . . . . ."
onChange={e => setInput(e.currentTarget.value)}
value={input}
/>
</div>
<div className="row">
<div className="col-12">
<div className="text-right">
<button type="submit" className="btn btn-primary mr-1" disabled={disable}>
Submit
</button>
<button
type="reset"
className="btn btn-primary"
value="Reset"
disabled={disable}
onClick={onReset}
>
<IoClose />
</button>
</div>
</div>
</div>
</Form>
</Formik>
{renderResult && <SearchResults query={query} posts={results} />}
</>
)
}
I've isolated where my issue is but having difficulty trying to resolve:
<Field
className="form-control"
name="query"
placeholder="Search . . . . ."
onChange={e => setInput(e.currentTarget.value)}
value={input}
/>
From within the Field's onChange and value are my problem. If I have everything as posted on submit the passed query doesn't exist. If I remove both and hard code a true for the submit button my query works.
Research
Custom change handlers with inputs inside Formik
Issue with values Formik
Why is OnChange not working when used in Formik?
In Formik how can I build a search bar that will detect input value to render the buttons?
You need to tap into the props that are available as part of the Formik component. Their docs show a simple example that is similar to what you'll need:
<Formik
initialValues={{ query: '' }}
onSubmit={(values, { setSubmitting }) => {
setInput('')
otherStuff()
}}
>
{formikProps => (
<Form className="mb-5">
<div className="form-group has-feedback has-clear">
<Field
name="query"
onChange={formikProps.handleChange}
value={formikProps.values.query}
/>
</div>
<button
type="submit"
disabled={!formikProps.values.query}
>
Submit
</button>
<button
type="reset"
disabled={!formikProps.values.query}
onClick={formikProps.resetForm}
>
</Form>
{/* ... more stuff ... */}
)}
</Formik>
You use this render props pattern to pull formiks props out (I usually call them formikProps, but you can call them anything you want), which then has access to everything you need. Rather than having your input, setInput, disable, and setDisable variables, you can just reference what is in your formikProps. For example, if you want to disable the submit button, you can just say disable={!formikProps.values.query}, meaning if the query value in the form is an empty string, you can't submit the form.
As far as onChange, as long as you give a field the correct name as it corresponds to the property in your initialValues object, formikProps.handleChange will know how to properly update that value for you. Use formikProps.values.whatever for the value of the field, an your component will read those updates automatically. The combo of name, value, and onChange, all handled through formikProps, makes form handing easy.
Formik has tons of very useful prebuilt functionality to handle this for you. I recommend hanging out on their docs site and you'll see how little of your own code you have to write to handle these common form behaviors.

Resources