How to access input elements from a React function - javascript

I currently have a form that is auto generated based on the amount of "Activities" a current user has. Each activity has a name and a value. My goal is to submit these values to the backend to update them. Yet I can't figure out how to reference these inputs. I was trying to read about using "ref"s, yet they come back with {current:null}
Here is the auto generated list (excuse the placeholder text)
When I inspect console here is what I find from the ref:
Here is my code:
import React, { useEffect } from "react";
import { useDispatch, useStore } from "react-redux";
import { connect } from "react-redux";
import * as actions from "../store/actions/patientSide";
export function ActivityTemplates() {
const dispatch = useDispatch();
const store = useStore();
const ref = React.createRef();
useEffect(() => {
// Update the document title using the browser API
dispatch(actions.getTodaysActivityTemplates());
}, []);
const activities = store.getState().patientSide.todays_activities;
const listedStuff = activities.map((activity) => (
<div>
{activity.activity_name}
<label for="value"> Value: </label>
<input
type="number"
id="value"
defaultValue={activity.value}
min="0"
max="10"
></input>
</div>
));
const saveActivities = () => {
var inputs = ref;
console.log(inputs);
// Insert code to run the call to the backend
};
return (
<div>
<h1> Activity Templates</h1>
<form id="form" onSubmit={saveActivities()} ref={ref}>
{listedStuff}
<input type="submit" name="save" />
</form>
</div>
);
}
export default ActivityTemplates;
I am very new to React and JS and honestly have very little idea of what I'm doing, but if someone could point me in the right direction that would be awesome!
EDIT: After sleeping on it, I've realized I've just been trying to force react into my HTML. I believe I should instead use a React Form Hook, and do it properly from the ground up.

<form onSubmit={handleOnSubmit}>
<label>User Name</label>
<input type="text" name="username" /><br/>
<label>Password</label>
<input type="password" name="password" /><br/>
<input type="submit" value="Submit" />
</form>
const handleOnSubmit = (event) => {
const formData = new FormData(event.target);
const formDetails = {};
event.preventDefault();
for (let entry of formData.entries()) {
formDetails[entry[0]] = entry[1];
};
console.log("formDetails", formDetails);
}

You are getting the input fields value from "FormData" on onSubmit.
const saveActivities = (event) => {
event.preventDefault();
const data = new FormData(event.target);
// Insert code to run the call to the backend
}

You need to store the value
const [value, setValue] = React.useState();
Then give your input a onChange={e => setValue(e.target.value)}
I would change the id though

Related

How to pass <form> data to an object array in React

I'm trying to make this simple component where I type a message in the input box and the component returns the message in a list underneath the input field. However when I click the submit button the only thing that appears below is a blank bullet point
import React, { useState } from 'react'
function Form(props) {
const [message, setMessage] = useState([])
const addMessageHandler = (event) => {
event.preventDefault()
const data = new FormData(event.target);
const _data = data.get('input')
setMessage([...message, { id: message.length, value: _data }])
}
return (
<div>
<form onSubmit={addMessageHandler} id='input'>
<label>Type a Message</label>
<input type='text'></input>
<button type='submit'>Submit</button>
</form>
<ul>
{
message.map(msg => (
<li key={msg.id}>{msg.value}</li>
))
}
</ul>
</div>
)
}
export default Form
All ways add "id" & "name" attributes to input fields.
<label htmlFor="chat_box">Type a Message</label>
<input type='text' id="chat_box" name="chatbox_input" />
now you can access input elements in e.currentTarget.elements, just make sure you have give unique names to input tags.
const addMessageHandler = (event) => {
event.preventDefault()
setMessage((message) => [...message, { id: message.length, value: e.currentTarget.elements['chatbox_input'].value }])
}

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);
}, []);

How to get React state array to permanently update

I'm learning Node and React and now know how to integrate them and am working on making registration and login using Node and React. I'm going step by step, so currently I'm trying to at least get the inputs and put them into state as an array, and then after I get that I will go to hashing the password, sending the data to Node and the database, et cetera.
At the moment however, I'm a little bit stuck here. I'm trying to enter the username and password into my "details" state and then render it on the screen (or console log it, or whatever), but when I do it it shows up very quickly and then disappears. Why is the details state reverting to an empty array? How do I fix it? I did some research on here but couldn't figure it out.
import { useState } from 'react';
function App() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [details, setDetails] = useState([]);
const readUsername = (e) => {
setUsername(e.target.value);
}
const readPassword = (e) => {
setPassword(e.target.value);
}
const updateDetails = () => {
setDetails([username, password]);
}
return (
<div>
<h1>Register</h1>
<form>
<label htmlFor="username" name="username">Username: </label>
<input htmlFor="username" name="username" onChange={readUsername} />
<br/>
<label htmlFor="password" name="password">Password: </label>
<input htmlFor="password" name="password" type="password" onChange={readPassword} />
<br/>
<button onClick={updateDetails}>Submit</button>
</form>
<h1>{details}</h1>
</div>
);
}
export default App;
with the onChange handler on your input's, it is considered a "controlled" component. you also need to assign the value prop.
<input onChange={readUsername} value={username} />
Forms in React have the default behaviour as in HTML: refreshing the page upon submission.
React state only exists during the component's life. When you refresh the page, the component is unmounted, and the state is lost.
To prevent the page refresh, use a function to handle the form submission, and prevent the default behaviour.
const handleSubmit = (e) => {
e.preventDefault();
}
return (
...
<form onSubmit={handleSubmit}>
...
</form>
...
);
}
View demo on codesandbox
Further reading:
Forms in React
Preventing default behaviour of events
You want to create a controlled input so you should pass the value={password} attribute
like this:
<input htmlFor="username" name="username" onChange={readUsername} value={username} />
Also, I'd change how you handle to form. Change the button to type="submit"
like this
<button type="submit">Submit</button>
And then handle the submit from the <form>
like this:
<form onSubmit={(event) => updateDetails(event)}
And then on the function, you can use the submit event like this for example
const updateDetails = (e) => {
event.preventDefault()
...rest of logic
}

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.

Clear an input field with Reactjs?

I am using a variable below.
var newInput = {
title: this.inputTitle.value,
entry: this.inputEntry.value
};
This is used by my input fields.
<input type="text" id="inputname" className="form-control" ref={el => this.inputTitle = el} />
<textarea id="inputage" ref={el => this.inputEntry = el} className="form-control" />
<button className="btn btn-info" onClick={this.sendthru}>Add</button>
Once I activate {this.sendthru} I want to clear my input fields. However, I am uncertain how to do so.
Also, as shown in this example, it was pointed out to me that I should use the ref property for input values. What I am unclear of is what exactly does it mean to have {el => this.inputEntry = el}. What is the significance of el in this situation?
Let me assume that you have done the 'this' binding of 'sendThru' function.
The below functions clears the input fields when the method is triggered.
sendThru() {
this.inputTitle.value = "";
this.inputEntry.value = "";
}
Refs can be written as inline function expression:
ref={el => this.inputTitle = el}
where el refers to the component.
When refs are written like above, React sees a different function object each time so on every update, ref will be called with null immediately before it's called with the component instance.
Read more about it here.
Declare value attribute for input tag (i.e value= {this.state.name}) and if you want to clear this input value you have to use this.setState({name : ''})
PFB working code for your reference :
<script type="text/babel">
var StateComponent = React.createClass({
resetName : function(event){
this.setState({
name : ''
});
},
render : function(){
return (
<div>
<input type="text" value= {this.state.name}/>
<button onClick={this.resetName}>Reset</button>
</div>
)
}
});
ReactDOM.render(<StateComponent/>, document.getElementById('app'));
</script>
I'm not really sure of the syntax {el => this.inputEntry = el}, but when clearing an input field you assign a ref like you mentioned.
<input type="text" ref="someName" />
Then in the onClick function after you've finished using the input value, just use...
this.refs.someName.value = '';
Edit
Actually the {el => this.inputEntry = el} is the same as this I believe. Maybe someone can correct me. The value for el must be getting passed in from somewhere, to act as the reference.
function (el) {
this.inputEntry = el;
}
I have a similar solution to #Satheesh using React hooks:
State initialization:
const [enteredText, setEnteredText] = useState('');
Input tag:
<input type="text" value={enteredText} (event handler, classNames, etc.) />
Inside the event handler function, after updating the object with data from input form, call:
setEnteredText('');
Note: This is described as 'two-way binding'
You can use input type="reset"
<form action="/action_page.php">
text: <input type="text" name="email" /><br />
<input type="reset" defaultValue="Reset" />
</form>
Now you can use the useRef hook to get some magic if you do not want to use the useState hook:
function MyComponent() {
const inputRef = useRef(null);
const onButtonClick = () => {
// #ts-ignore (us this comment if typescript raises an error)
inputRef.current.value = "";
};
return (
<>
<input ref={inputRef} type="text" />
<button onClick={onButtonClick}>Clear input</button>
</>
);
}
As I mentioned, if you are using useState that is the best way. I wanted to show you also this special approach.
Also after React v 16.8+ you have an ability to use hooks
import React, {useState} from 'react';
const ControlledInputs = () => {
const [firstName, setFirstName] = useState(false);
const handleSubmit = (e) => {
e.preventDefault();
if (firstName) {
console.log('firstName :>> ', firstName);
}
};
return (
<>
<form onSubmit={handleSubmit}>
<label htmlFor="firstName">Name: </label>
<input
type="text"
id="firstName"
name="firstName"
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
/>
<button type="submit">add person</button>
</form>
</>
);
};
You can use useState:
import React, { useState } from 'react';
const [inputTitle, setInputTitle] = useState('');
then add value to your input component:
render() {
<input type="text" onChange={(e) => setInputTitle(e.target.value)}
value={inputTitle} />
<button onClick={handleSubmit} type="submit">Submit</button>
}
On your submit handler function:
setInputTitle('');
document.querySelector('input').defaultValue = '';
On the event of onClick
this.state={
title:''
}
sendthru=()=>{
document.getElementByid('inputname').value = '';
this.setState({
title:''
})
}
<input type="text" id="inputname" className="form-control" ref={el => this.inputTitle = el} />
<button className="btn btn-info" onClick={this.sendthru}>Add</button>
I used the defaultValue property, useRef, and onClick to achieve this.
let ref = useRef()
and then inside the return:
<input type="text" defaultValue="bacon" ref={ref} onClick={() => ref.current.value = ""} />
also if you want to use onChange for the input it wouldn't require any more configuration and you can just use it. If you want to have a dynamic defaultValue then you absolutely can, with useState.
A simple way to reset the input in React is by implementing the onBlur inside the input.
onBlur={cleanSearch}
ej:
const [search, setSearch] = useState('')
const handleSearch = ({target}) =>{
setSearch(target.value)
}
const cleanSearch = () =>setSearch('')
<input
placeholder="Search…"
inputProps={{ 'aria-label': 'search' }}
value={search}
onChange={handleSearch}
onBlur={cleanSearch}
/>
The way I cleared my form input values was to add an id to my form tag.
Then when I handleSubmit I call this.clearForm()
In the clearForm function I then use document.getElementById("myForm").reset();
import React, {Component } from 'react';
import './App.css';
import Button from './components/Button';
import Input from './components/Input';
class App extends Component {
state = {
item: "",
list: []
}
componentDidMount() {
this.clearForm();
}
handleFormSubmit = event => {
this.clearForm()
event.preventDefault()
const item = this.state.item
this.setState ({
list: [...this.state.list, item],
})
}
handleInputChange = event => {
this.setState ({
item: event.target.value
})
}
clearForm = () => {
document.getElementById("myForm").reset();
this.setState({
item: ""
})
}
render() {
return (
<form id="myForm">
<Input
name="textinfo"
onChange={this.handleInputChange}
value={this.state.item}
/>
<Button
onClick={this.handleFormSubmit}
> </Button>
</form>
);
}
}
export default App;

Categories