How to get input text value on click - reactjs

I want to Know how to get the input text values in ReactJS using simple onclick event.I Know that it can be possible to do it like below code:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
Value: ""
};
}
render() {
const { library } = this.state;
return (
<div>
<input type="text" onChange={this.handleChange} />
<button type="button" onClick={this.handleSearch}>
save
</button>
</div>
);
}
handleChange = evt => {
this.setState({ Value: e.target.value });
};
handleSearch = evt => {
console.log(this.state.Value);
};
}
ReactDOM.render(<App />, document.getElementById("ResultContainer"));
I want to know is there any other way to get the input text without using onChange={ this.handleChange } ?

Like others have suggested, you could use a ref if you're feeling adventurous, but your code works as is.
However, just for learning purposes, you can use a ref to access the traditional DOM aspects of the mark-up that you would find using Vanilla JavaScript and HTML.
Simply create a ref variable and pass it to the input's ref attribute. See working sandbox: https://codesandbox.io/s/floral-lake-z9szd
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
Value: ""
};
}
inputText = React.createRef();
handleSearch = () => {
if (this.inputText.current) {
console.log(this.inputText.current.value);
}
};
render() {
return (
<div>
<input type="text" ref={this.inputText} />
<button type="button" onClick={this.handleSearch}>
save
</button>
</div>
);
}
}

Same concept but simpler with Functional Component and react hooks:
const App =()=>{
const [value,setValue]=React.useState();
const handleSearch = ()=>{
console.log(value)
}
return(
<div>
<input type="text" value={value} onChange={e=>setValue(e.target.value)} />
<button type="button" onClick={handleSearch}>
save
</button>
</div>
)
}

Dont know about reasoning why you want to to it different way. But sure there are tons of possibilities. First of all => when you are working on react application. Never forget that react is jsut layer above the DOM (when working on web app). So when you want to do some crazy stuff let react expose dom to you. In case of event handler you can get real dome node through event.target, which is button element. So you can do something like event.target.parentNode.childNodes[0].value or event.target.previousSibling.value. Imagination can be infinite you know :). Using ref is also another possible solution. But always think about: One time, someone will try to read this code. So do it easier for him.

Related

Focus an input after clicking on a button

I am currently trying to learn React by making a Todo list (original I know). There a lot of concepts I haven't learnt yet (I'm still using class components) but I was wondering is there a recommended way to focus the input that appears when the edit button is pushed?
I tried using createRef but it still seems not to work. I'm wondering I the input should be a separate component that focuses onMount?
Any direction would be appreciated:
export class Item extends Component {
constructor(props){
super(props)
this.editInput = React.createRef()
this.state = {
editView: false
}
this.handleRemove = this.handleRemove.bind(this);
this.toggleView = this.toggleView.bind(this);
this.editMode = this.editMode.bind(this);
}
handleRemove(e){
this.props.remove(this.props.detail);
}
toggleView(){
this.setState(prevState => (
{editView: !prevState.editView }
))
}
editMode(){
this.toggleView();
this.editInput.current.focus();
}
render() {
const itemView = !this.state.editView ?<div className="item">{this.props.detail}</div> : <input ref={this.editInput} className="edit-item-input" placeholder={this.props.detail + "..."}></input> ;
return (
<div className="item-container">
{itemView}
<div className="buttons">
<button onClick={this.editMode} className="button button-edit">Edit</button>
<button onClick={this.handleRemove} className="button button-delete">Delete</button>
</div>
</div>
)
}
}
You could add the React autoFocus property, on the input element, and it should work as you want.

How access specific DOM in React js

I'm trying to get input tags' HTML inner values when submitting a form.
private handleSubmit = (event: any) => {
event.preventDefault();
console.log(event.currentTarget);
};
When the submit the form, it calls the function handleSubmit and it console logs the following.
Under the form tag, the first div has username value and the second div has password value. I would like to acess the two values. I think I should use DOM to do that, but can't be sure if I'm going for the right direction cuz I found some postings saying using DOM is not recommended.
Can anyone explain how I can acheive this?
Ideally you should update your state as the user enters information, and then access the data from the state. This would also allow you to run any validation on the data prior to it going into the state if you'd like.
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
username: null,
password: null
}
this.submitForm = this.submitForm.bind(this);
this.updateState = this.updateState.bind(this);
}
updateState (e) {
this.setState({[e.target.name]: e.target.value})
}
submitForm (e) {
e.preventDefault();
console.log(this.state);
}
render() {
return (
<div className="App">
<form onSubmit={this.submitForm}>
<input type="text" name="username" placeholder="username" onChange={this.updateState} /><br />
<input type="password" name="password" placeholder="password" onChange={this.updateState} /><br />
<button type="submit">Submit</button>
</form>
</div>
);
}
}
export default App;
The above code does the following:
Stores default values for username and password. While this isn't required, it makes the code more readable
binds this to functions that need to access state
Uses an updateState() function that is called onChange of the inputs
updateState uses the name attribute of the input as the key for the state
You could customize the updateState() function to do some validation, before saving to state if you'd like.
Excessive Rendering
ReactJS is pretty smart to no re-render the REAL DOM if your render() method doesn't actually rely on the state values that were updated; however, if you'd like to prevent ReactJS from even creating the Virtual DOM and comparing, you could utilize the shouldComponentUpdate() lifecycle hook.
In the particular example above, since render doesn't rely on ANYTHING in state, you could simply add the following method:
shouldComponentUpdate(prevState, nextState) {
return false;
}
That will prevent the render method from EVER re-rendering, which is most likely not going to work in a normal component, thus you could do something like this instead, only re-rendering on values you care about.
shouldComponentUpdate(prevState, nextState) {
if (nextState.email !== prevState.email) {
return true
}
return false;
}
Demo
https://repl.it/#AnonymousSB/SO53689072
If you want to use the DOM, once you have the form element (event.currentTarget in your case), you can use the .elements property to access a list of child inputs and buttons.
Alternatively, you can use React refs to keep track of the underlying HTML element when it's rendered.
render() {
return ... <input ref={(e) => this._name = e; } ....> ... ;
}
handleSubmit(e) {
var name = this._name ? this._name.value : '';
....
}
This can achieve what you want to
class Login extends Component{
state={
username:"",
password:""
}
onChange = (event)=>{
event.preventDefault()
this.setState({
[event.target.name]: event.target.value})
}
onSubmit = (event)=>{
event.preventDefault()
// submit whatever is in state from here
console.log(this.state)
}
render(){
return(<div>
<form onSubmit={handleSubmit}>
<input type="text" name="username" onChange={this.onChange} /><br />
<input type="password" name="password" onChange={this.onChange} /><br />
<button type="submit">Submit</button>
</form>
</div>)
}
}

React form input won't let me change value

I have a component in a React class in my Laravel project which is a simple form with one input field. It houses a phone number which I have retrieved from the database and passed back through the reducer and into the component as a prop. Using this, I have passed it through to the module as a prop which then populates the field with the currently saved value:
<OutOfOfficeContactNumberForm
show={props.showOutOfOffice}
value={props.outOfOfficeNumber}
handleChange={console.log("changed")}
/>
I have a handleChange on here which is supposed to fire a console log, but it only ever displays on page load. Here is my form module class:
class OutOfOfficeContactNumberForm extends React.Component {
render() {
const { show, value, handleChange } = this.props;
if(!show) return null;
return (
<div>
<p>
Please supply an Out of Office contact number to continue.
</p>
<InputGroup layout="inline">
<Label layout="inline" required={true}>Out of Office Contact Number</Label>
<Input onChange={handleChange} value={value} layout="inline" id="out-of-office-number" name="out_of_office_contact_number" />
</InputGroup>
</div>
);
}
}
export default (CSSModules(OutOfOfficeContactNumberForm, style));
The form is embedded in my parent component, as follows:
return (
<SectionCategoriesSettingsForm
isSubmitting={this.state.isSubmitting}
page={this.props.page}
show={this.props.show}
categories={this.props.categories}
submitSectionCategoriesSettings={this._submit.bind(this, 'add')}
updateSelectedCategories={this._updateSelectedCategories.bind(this)}
selectedCategoryIds={this.state.selectedCategoryIds}
storedUserCategories={this.props.selectedCategories}
outOfOfficeNumber={this.state.outOfOfficeNumber}
onUpdateContactNumber={this._updateContactNumber.bind(this)}
/>
);
In my componentWillReceiveProps() function, I set the state as follows:
if (nextProps.selectedCategories && nextProps.selectedCategories.length > 0) {
this.setState({
outOfOfficeNumber: nextProps.outOfOfficeNumber,
selectedCategoryIds: nextProps.selectedCategories.map(c => c.id)
});
}
I'm pretty sure the reason it's not changing is because it's pre-loaded from the state which doesn't change - but if I cannot edit the field how can I get it to register a change?
EDIT: Just to clarify there are also checkboxes in this form for the user to change their preferences, and the data retrieved for them is set the same way but I am able to check and uncheck those no problem
Changes:
1- onChange expect a function and you are assigning a value that's why, put the console statement inside a function and pass that function toOutOfOfficeContactNumberForm component , like this:
handleChange={() => console.log("changed")}
2- You are using controlled component (using the value property), so you need to update the value inside onChange function otherwise it will not allow you to change means input values will not be not reflect in ui.
Check example:
class App extends React.Component {
state = {
input1: '',
input2: '',
}
onChange = (e) => this.setState({ input2: e.target.value })
render() {
return(
<div>
Without updating value inside onChange
<input value={this.state.input1} onChange={console.log('value')} />
<br />
Updating value in onChange
<input value={this.state.input2} onChange={this.onChange} />
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app' />
I think the best way is when you get data from database put it to state and pass the state to input and remember if you want to see input changes in typing, use a function to handle the change and that function should change state value.
class payloadcontainer extends Component {
constructor(props) {
super(props)
this.state = {
number:1
}
}
render() {
return (
<div>
<input value={this.state.number} onChange={(e)=>this.setState({number:e.target.value})}></input>
<button onClick={()=>this.props.buyCake(this.state.number)}><h3>buy {this.state.number} cake </h3></button>
</div>
)
}
}

Handle State change in React with ONE handleChange method for both selectFields and TextFields

I would like to know how I can handle state changes with ONE handleChange method.
I handle two text fields with handleChange, but I cant figure out how I can handle changes on SelectField as well, with the same handleChange method.
When change the Spot Type from Kitesurfing to Diving and console.log this.state I get this:
form
:
description: "This is a amazing spot in Spain."
name: "Blue water"
spotType: "Kitesurfing"
undefined: undefined <-- this is from the SelectField, when changing from Kitesurfing to Diving..
AddASpot.js
import React, { Component } from "react";
import TextField from "material-ui/TextField";
import SelectField from "material-ui/SelectField";
import MenuItem from "material-ui/MenuItem";
import RaisedButton from "material-ui/RaisedButton";
class AddASpot extends Component {
constructor(props) {
super(props);
this.state = {
form: {
spotType: "Kitesurfing"
}
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange = event => {
const target = event.target;
const value = target.type === "checkbox" ? target.checked : target.value;
const name = target.name;
const form = Object.assign({}, this.state.form);
form[name] = value;
this.setState({ form });
};
handleSubmit = () => {
console.log(this.state);
};
render() {
return (
<div>
<h1>Add a new Spot</h1>
<TextField
name="name"
onChange={this.handleChange}
hintText="Name of Spot"
/>
<br />
<SelectField
floatingLabelText="Spot Type"
name="spotType"
value={this.state.form.spotType}
onChange={this.handleChange}
>
<MenuItem value="Diving" primaryText="Diving" />
<MenuItem value="Kitesurfing" primaryText="Kitesurfing" />
<MenuItem value="Surfing" primaryText="Surfing" />
<MenuItem value="Spearfishing" primaryText="Spearfishing" />
</SelectField>
<br />
<TextField
name="description"
onChange={this.handleChange}
hintText="Description of the Spot"
multiLine={true}
rows={3}
rowsMax={4}
/>
<br />
<RaisedButton
onClick={this.handleSubmit}
label="Add Spot"
primary={true}
/>
</div>
);
}
}
export default AddASpot;
Your logic inside of the handleChange method needs some reconsidering. It seems you are trying to make things a lot more complicated than they need to be. Your example is hard to reproduce, unless someone wants to build this themselves, which is probably why no one has answered it yet.
I did however get a similar type of example working in Codepen, without the material UI package you are using, as I do not know how to add those packages properly into Codepen.
To hopefully make this easier for you, I just got the select menu working for you, and ignored the other ones for now. Hopefully this will help you visualize how to incorporate the logic to handle the others properly.
Check the pen here. You'll see that I changed your handleChange method to two lines of code, without the need for using Object.assign.
If you can get a full working version of your specific example, I'd be glad to change the answer to reflect that, but like I said, it is not easy to reproduce for people on here.
handleChange = event => {
const value = event.target.value
this.setState({ form: { spotType: value } })
};
I did not figure out how to handle this with only one method so I created one unique for the SelectFields as this method requires three props.
handleChangeSelectField = (event, index, value) => {
const form = Object.assign({}, this.state.form);
form["spotType"] = value;
this.setState({ form });
};

how react programmatically focus input

I'm trying to implement a very simple use case, a UI feature, where:
There is a label with some content in it
If clicked, a text input replaces it with the content of label available
User can edit the content
When enter is pressed, the input hides and label is back with updated content
I could get finally all correct (in fact with a MongoBD backend, redux, etc.), and the only thing I couldn't ever do (paying a complete day in googling and reading S.O.F similar posts) was this:
When my text input appears, I can't transfer focus to it! First I tired this way:
<div className={((this.state.toggleWordEdit) ? '' : 'hidden')}>
<input id={this.props.word._id} className="form-control"
ref="updateTheWord"
defaultValue={this.state.word}
onChange={this.handleChange}
onKeyPress={this.handleSubmit}
autoFocus={this.state.toggleWordEdit}/></div>
<div className={((this.state.toggleWordEdit) ? 'hidden' : '')}>
<h3 onClick={this.updateWord}>
{this.state.word}</h3>
</div>
but autoFocus sure didn't work (I "guess" because the form is rendered, but in hidden state, making autoFocus useless).
Next I tried in my this.updateWor, many of suggestions I found on google and S.O.F.:
this.refs.updateTheWord.focus();
which together with similar suggestions all didn't work. Also I tried to fool React just to see if at all I can do something! I used real DOM:
const x = document.getElementById(this.props.word._id);
x.focus();
and it didn't work either. One thing I even could not understand to put into word is a suggestion like this:
having ref as a method (I "guess")
I didn't even try it because I have multiples of these components and I need ref to further get value of, per component, and I couldn't imagine if my ref is not named, how I could get the value of!
So could you please give an idea, helping me to understand that in case I'm not using a Form (because I need a single input box replacing a label) how I could set its focus when it's CSS (Bootstrap) class is losing 'hidden' please?
The way you have used refs is not the most preferred way or else its not the best practice anymore . try some thing like this
class MyClass extends React.Component {
constructor(props) {
super(props);
this.focus = this.focus.bind(this);
}
focus() {
this.textInput.current.focus();
}
render() {
return (
<div>
<input
type="text"
ref={(input) => { this.textInput = input; }} />
<input
type="button"
value="Set Focus"
onClick={this.focus}
/>
</div>
);
}
}
Update
From React 16.3 upwards you can use the React.createRef() API
class MyClass extends React.Component {
constructor(props) {
super(props);
// create a ref to store the textInput DOM element
this.textInput = React.createRef();
this.focus = this.focus.bind(this);
}
focus() {
// Explicitly focus the text input using the raw DOM API
// Note: we're accessing "current" to get the DOM node
this.textInput.current.focus();
}
render() {
// tell React that we want to associate the <input> ref
// with the `textInput` that we created in the constructor
return (
<div>
<input
type="text"
ref={this.textInput} />
<input
type="button"
value="Set Focus"
onClick={this.focus}
/>
</div>
);
}
}
From React 18.xx upwards you can use the useRef Hook
import React, { useRef } from "react";
export const Form = () => {
const inputRef = useRef(null);
const focus = () => {
inputRef.current.focus();
};
return (
<div>
<input type="text" ref={inputRef} />
<input type="button" value="Set Focus" onClick={focus} />
</div>
);
};
Just add autofocus attribute to the input. (of course in JSX it is autoFocus)
<input autoFocus ...
useFocus hook
// General Focus Hook
const useFocus = (initialFocus = false, id = "") => {
const [focus, setFocus] = useState(initialFocus)
const setFocusWithTrueDefault = (param) => setFocus(isBoolean(param)? param : true)
return ([
setFocusWithTrueDefault, {
autoFocus: focus,
key: `${id}${focus}`,
onFocus: () => setFocus(true),
onBlur: () => setFocus(false),
},
])
}
const FocusDemo = () => {
const [labelStr, setLabelStr] = useState("Your initial Value")
const [setFocus, focusProps] = useFocus(true)
return (
<> {/* React.Fragment */}
<input
onChange={(e)=> setLabelStr(e.target.value)}
value={labelStr}
{...focusProps}
/>
<h3 onClick={setFocus}>{labelStr}</h3>
</>
)
}
For a more complete demo click here.
In addition to the previous answers, I've added setTimeout to make it work
handleClick() {
if (this.searchInput) {
setTimeout(() => {
this.searchInput.focus();
}, 100);
}
}
where searchInput is the jsx ref of the input
<input
type="text"
name="searchText"
ref={(input) => { this.searchInput = input; }}
placeholder="Search" />
and the handleClick() is an onClick handler to any element
#BenCarp's answer in typescript
Pass the inputRef to an input and just call setFocus to set the focus to it.
export const useInputFocus = (): [MutableRefObject<HTMLInputElement | undefined>, () => void] => {
const inputRef = useRef<HTMLInputElement>();
const setFocus = (): void => {
const currentEl = inputRef.current;
if (currentEl) {
currentEl.focus();
}
};
return [inputRef, setFocus];
};
Use componentDidUpdate method to every time update the component
componentDidUpdate(prevProps, prevState) {
this.input.focus();
}
You can use "useRef" hook and make a reference to your input control, then use your reference.current.focus()

Resources