edit text input React - javascript

Is there any way of inject text of database into the input to be editable? not like placeholder.
Here is a picture as example.
In this case the text is placed as placeholder and obviously can not be editable without erase all.
Here is the code:
<div style={modalStyle} className={classes.paper}>
<form className="update-note create-note">
<input
className="input-edit-note"
name="title"
onChange={(e) => setTitle(e.currentTarget.value)}
value={title}
placeholder={props.title}
/>
<textarea
name="content"
onChange={(e) => setContent(e.currentTarget.value)}
value={content}
placeholder={props.content}
/>
<Fab onClick={submitNote}>
<AddCircleIcon />
</Fab>
</form>
</div>

Whatever you put in value={...} will be visible to edit in the textfield.
If it's props that you want to merge with component local data then I'd suggest doing so via useState and useEffect
Either this:
const Example = (props) => {
const [title, setTitle] = useState(props.title);
...
}
or like this
const Example = (props) => {
const [title, setTitle] = useState('');
useEffect(() => {
setTitle(props.title);
}, [props.title]);
...
}
And then use the value in the input tag
<input
...
value={title}
...
/>
Example component:
// When initiating this component, make sure to pass "title" as props
const Example = (props) => {
// Title is bound to state within this component
const [title, setTitle] = useState(props.title);
const _onChangeTitle = e => {
setTitle(e.target.value);
}
return (
<input
className="input-edit-note"
name="title"
onChange={_onChangeTitle}
value={title} // title will always be state title
placeholder={props.title} // props.title will always remain the same
/>
)
}

once you get your data from you db save it in your component state as i see you're already doing:
const MyComponent = (props) => {
const [title, setTitle] = useState(props.title);
...
}
then set theinput's value equal to the title data you recieve from your db.
At the onChange trigger the setTitle function that will update your title state.
<input
className="YourProfileInput"
placeholder="Insert Title"
value={title}
onChange={(e) => setTitle(e.currentTarget.value)}
/>

Related

Failed to get state by useLocation while it has Object data in state

First.js
import { useState } from "react";
import { Link } from "react-router-dom";
const First = () => {
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
}
return (
<div className="First">
<h1>This is First Input Page</h1>
<form onSubmit={handleSubmit}>
<dd>data 1</dd>
<input
type="text"
value={name}
onChange={(e) =>
setName(e.target.value)
}
required
></input>
<dd>data 2</dd>
<input
type="text"
value={phone}
onChange={(e) =>
setPhone(e.target.value)
}
required
></input><br/>
<Link to={'/second'} state={{ state: { name : name , phone : phone } }}><button>submit</button></Link>
</form>
</div>
);
}
export default First;
I try to send Object data using Link/state to another component.
Second.js
import {useLocation} from 'react-router-dom';
const Second = () => {
const location = useLocation();
console.log(location.state);
console.log(location.state.name);
return (
<div className="Second">
<h1>This is Second Input Page</h1>
<form>
<dd>data 3</dd>
<input></input>
<dd>data 4</dd>
<input></input><br/>
<button>submit</button>
</form>
</div>
);
}
export default Second;
However, while I can access to (location.state), I can not access to (location.state.name). Why is that?
Output
state: {name:ย 'Myname',ย phone:ย 'myphone'}
[[Prototype]]: Object
--------------------
undefined
The output shows that the code line "console.log(location.state);" works, but to the "console.log(location.state.name);", it shows undefined.
It's because you passed an object with state as the root property, i.e.
state={{ state: { name: name, phone: phone } }}
so to access it in the receiving route it is location.state.state.name.
You really don't need to nest the data you want to pass under a state property when using the Link component, it's not quite the same as when using the navigate function.
<Link to="/second" state={{ name, phone }}>
<button>submit</button>
</Link>
It may also be considered semantically incorrect HTML to nest a button element within an anchor tag (via Link) element. Use the useNavigate hook and issue an imperative navigation action from the form's submit handler. In this case the navigate function's second argument, the options object, *does* expect the state to be passed under the state` property.
Example:
import { Link, useNavigate } from "react-router-dom";
const First = () => {
const navigate = useNavigate();
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
navigate("/second", { state: { name, phone } });
};
return (
<div className="First">
<h1>This is First Input Page</h1>
<form onSubmit={handleSubmit}>
<dd>data 1</dd>
<input
type="text"
value={name}
onChange={(e) =>
setName(e.target.value)
}
required
/>
<dd>data 2</dd>
<input
type="text"
value={phone}
onChange={(e) =>
setPhone(e.target.value)
}
required
/>
<br/>
<button>submit</button>
</form>
</div>
);
};
export default First;

Axios.post keeps sending empty objects to my API

I am trying to post new information about a cow to my cow API, however, everytime i hit the submit button on my frontend, it seems to be sending an empty object rather than the name of the cow, description of the cow, and image of the cow (via url). What is causing it to send an empty object versus my desired data?
Here is the frontend code:
import React, { useEffect, useState } from 'react';
import axios from 'axios';
import './App.css';
const baseUrl = "http://localhost:3001/api/cows"
function Display({setNameOfCow, setImageOfCow, setDescriptionOfCow, nameOfCow, imageOfCow, descriptionOfCow}) {
axios.get(baseUrl)
.then(res => res.data)
.then(res => {
setNameOfCow(res.name)
setImageOfCow(res.image)
setDescriptionOfCow(res.description)
})
return (
<div>
<p>{nameOfCow}</p>
<img src={imageOfCow}/><p>{descriptionOfCow}</p>
</div>
)
}
function Input({setNameOfCow, setImageOfCow, setDescriptionOfCow, nameOfCow, imageOfCow, descriptionOfCow}) {
function handleSubmit(e) {
e.preventDefault()
let newObject = {
name: nameOfCow,
description: descriptionOfCow,
image: imageOfCow
}
axios.post(baseUrl, newObject)
}
return (
<div>
<form>
<label htmlFor="name">name: </label>
<input type="text" id="name" onChange={(e) => {
const eTarget = e.target.value
setNameOfCow(eTarget)}}/><br></br>
<label htmlFor="description">description: </label>
<input type="text" id="description" onChange={(e) => {
const eTargetDesc = e.target.value
setDescriptionOfCow(eTargetDesc)}}/><br></br>
<label htmlFor="image">image url: </label>
<input type='text' id="image" onChange={(e) => {
const eTargetImage = e.target.value
setImageOfCow(eTargetImage)}}/><br></br>
<button type="submit" onSubmit={handleSubmit}>Add a cow!</button>
</form>
</div>
)
}
function App() {
const [nameOfCow, setNameOfCow] = useState('')
const [descriptionOfCow, setDescriptionOfCow] = useState('')
const [imageOfCow, setImageOfCow] = useState('')
return (
<div className="App">
<Input imageOfCow={imageOfCow} setNameOfCow={setNameOfCow} setDescriptionOfCow={setDescriptionOfCow} setImageOfCow={setImageOfCow} />
<Display setNameOfCow={setNameOfCow} setImageOfCow={setImageOfCow} setDescriptionOfCow={setDescriptionOfCow} nameOfCow={nameOfCow} imageOfCow={imageOfCow} descriptionOfCow={descriptionOfCow} />
</div>
);
}
export default App
and here is the image showing the empty objects being posted:
Looking into your Input component props:
function Input({setNameOfCow, setImageOfCow, setDescriptionOfCow, nameOfCow, imageOfCow, descriptionOfCow}) {...
We can see that you missing to pass this props when using this component:
<Input imageOfCow={imageOfCow} setNameOfCow={setNameOfCow} setDescriptionOfCow={setDescriptionOfCow} setImageOfCow={setImageOfCow} />
The correct way to use is something like:
<Input
imageOfCow={imageOfCow}
nameOfCow={nameOfCow}
descriptionOfCow={descriptionOfCow}
setNameOfCow={setNameOfCow}
setDescriptionOfCow={setDescriptionOfCow}
setImageOfCow={setImageOfCow}
/>
Also the correct way to prevent the form default behavior is setting the onSubmit and the handleSubmit at the form attribute (you can remove from the button):
<form onSubmit={handleSubmit}>
Otherwise a very nice change is to put your axios request inside a useEffect hook to prevent your app from making request every time it re-render.
Using something like this the app will make the request only at the first component render.
const getCow = async (baseUrl) => {
const cow = await axios.get(baseUrl);
setNameOfCow(cow.name);
setImageOfCow(cow.image);
setDescriptionOfCow(cow.description);
};
useEffect(() => {
getCow(baseUrl);
}, []);

using useRef in input to avoid re render in appication

I want to implement useRef so that the component in which my input tag is should not re-render on value change. If we use useState it will re-render the entire component on every key pressed.
This is how we usually do it but this will re-render the entire component on every change.
const [name, setName] = useState('');
return(
<input type="text" placeholder="Name" value={name} onChange={e => setName(e.target.value)} />
)
I want to do this using useRef to avoid it
const name = useRef("");
const handleName = (e) => {
name.current = e.target.value
};
return(
<input type="text" placeholder="Name" value={name.current.value} onChange={handleName} />
)
but it's not working for some reason?
Change your input tag to this (inside JSX):
<input type="text" placeholder="Name" ref={name} onChange={handleName} />
Instead of value={name.current.value} use ref={name}. It should fix the issue.
Full code :
import { useRef } from "react";
export default function App() {
const name = useRef('');
const handleName = (e) => {
name.current = e.target.value
document.getElementById('test').innerText = name.current
};
return(
<>
<input type="text" placeholder="Name" ref={name} onChange={handleName} />
<p id='test'></p>
</>
)
}
if you want to avoid rendering on change, you can just pass ref to the input element. and whenever required you can get the value from ref as used in the handleSubmit method below. Html input element will maintain its state:
const nameRef = useRef(null);
const handleSubmit = () => {
console.log(nameRef.current.value);
};
return(
<input type="text" ref={nameRef} placeholder="Name" />
)

Not able to render api response data into form

i am not able to render api response to form, i am using same form for add and for edit too. i want when i click on Add button it should show initial empty value , but when i click edit button , it should so particular user data , but i am not able to achieve it.
I have tried
import React, { useState, useContext, useEffect } from "react";
import { useParams, useLocation } from "react-router-dom";
import { globalC } from "./context";
export default function DashboardForm() {
const { detail, apiCalling } = useContext(globalC);
useEffect(() => {
apiCalling(id);
}, []);
const { pathname } = useLocation();
const action = pathname.split("/")[1];
const [name, setName] = useState(action === "add" ? "" : detail.name);
const [username, setUsername] = useState("");
const [email, setEmail] = useState("");
const { id } = useParams();
return (
<div style={{ height: "100vh" }}>
<form>
<input
name="name"
type="text"
placeholder="name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<br />
<input
name="username"
type="text"
placeholder="username"
onChange={(e) => setUsername(e.target.value)}
/>
<br />
<input
name="email"
type="text"
placeholder="email"
onChange={(e) => setEmail(e.target.value)}
/>
</form>
</div>
);
}
i am use class based context api , user get api is called in context,
Codesandbox link : link
login and go to dashboard to try the example
Mind that your useState for name will be first called when the API call hasn't succeeded yet, giving you an empty name. Then once you do get the proper name in detail, the state is already created.
One solution would be something like:
if (!name && detail.name) {
setImmediate(() => setName(detail.name));
}
So once the API call gave you the name, and while the name input field is still empty, update it with the received name.
Another solution is to only show the form once the API request succeeded, and show a loading screen in the meantime.

Displaying local storage values in a text-area with react-hooks

I'm trying to make a note taking app in React.
I have managed to save state on local storage.
My goal is to display the local storage 'notes' in the textarea on render and refresh. So far on refresh the place holder is displayed on render.
I want to:
If no notes in local storage display place holder
If notes are present in local then display them in the text area.
Heres the code:
const [notes, setNotes] = useState("")
useEffect(() => {
const notes = localStorage.getItem("notes")
if (notes) {
setNotes(JSON.parse(notes))
}
})
const handleChange = e => {
setNotes(e.target.value)
localStorage.setItem("notes", JSON.stringify(e.target.value))
}
return (
<form>
<label for="pad">
<span>Add your notes</span>
<textarea
rows="10"
placeholder="Add notes here ๐Ÿ“"
name="pad"
onChange={handleChange}
></textarea>
</label>
</form>
)
Use textarea value with notes variable.
You don't need useEffect for this example.
Even if you want to use it please add your dependency array.
export default function App() {
const localNotes = localStorage.getItem("notes");
const [notes, setNotes] = useState(localNotes);
const handleChange = e => {
localStorage.setItem("notes", e.target.value);
setNotes(e.target.value);
};
return (
<form>
<label for="pad">
<span>Add your notes</span>
<textarea
rows="10"
placeholder="Add notes here ๐Ÿ“"
name="pad"
value={notes}
onChange={handleChange}
/>
</label>
</form>
);
}
Working example https://codesandbox.io/s/still-moon-bmuof
1) You should bind the notes state to TextArea's value props.
2) You need to add an empty array as the dependency array for the useEffect hook, such that the method within it will only run once when the component is rendered. This will ensure that the state is updated with the values from localStorage when the component is mounted.
const [notes, setNotes] = useState("")
useEffect(() => {
const notes = localStorage.getItem("notes")
if (notes) {
setNotes(notes)
}
}, [])
const handleChange = e => {
const { value } = target
setNotes(e.target.value)
localStorage.setItem("notes", value))
}
return (
<form>
<label for="pad">
<span>Add your notes</span>
<textarea
rows="10"
placeholder="Add notes here ๐Ÿ“"
name="pad"
onChange={handleChange}
value={notes}
></textarea>
</label>
</form>
)

Categories