React input cursor position moves to the end? - reactjs

I came across with this scenario where I want to "sanitize" the input before calling onChange, however even without re-render, the cursor moves to the end. why?
class Input extends React.Component {
state = { value: this.props.value };
onChange = e => {
let nextValue = e.target.value;
if (!/[0-9]/.test(nextValue)) {
this.setState({ value: nextValue });
}
};
render() {
console.log("render");
return (
<input type="text" value={this.state.value} onChange={this.onChange} />
);
}
}
ReactDOM.render(<Input value="type something here" />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"/>

You can use onKeyPress to sanitize an input before onChange, without "side effects".
Code Sandbox: https://codesandbox.io/s/9jlm59n52r
import React from "react";
import ReactDOM from "react-dom";
class Input extends React.Component {
state = { value: this.props.value };
handleKeyPress = e => {
let keyPressed = e.key;
if (/[0-9]/.test(keyPressed)) {
e.preventDefault();
}
};
handleChange = e => {
this.setState({ value: e.target.value });
};
render() {
return (
<input
type="text"
value={this.state.value}
onKeyPress={this.handleKeyPress}
onChange={this.handleChange}
/>
);
}
}
ReactDOM.render(
<Input value="type something here" />,
document.getElementById("root")
);
EDIT:
Sanitize input on paste:
handlePaste = e => {
let pastedText = e.clipboardData.getData("text/plain");
if (/[0-9]/.test(pastedText)) {
e.preventDefault();
}
}
...
<input
...
onPaste={this.handlePaste}
...
/>

Related

Why my onInput doesn't work to change props.name?

I am learning React.js and I want to use onInput event to change the name, but it doesn't work.
Why is this happening? Do I write the wrong function(OnInputChange)?
Here is my app.js
import React, { Component } from "react";
import UserInput from "./Components/UserInput";
import UserOutput from "./Components/UserOutput";
class App extends Component {
state = {
Username: [{ name: "Jacky" }]
};
OnInputChange = event => {
this.setState({
Username: [{ name: "event.target.value" }]
});
};
render() {
return (
<div>
<UserInput OnInput={this.OnInputChange} />
<UserOutput name={this.state.Username[0].name} />
</div>
);
}
}
export default App;
my UserInput.js:
import React from "react";
const UserInput = () => {
return (
<div>
<input type="text" />
</div>
);
};
export default UserInput;
my UserOutput.js:
import React from "react";
const UserOutput = props => {
return (
<div>
<p>I am {props.name}</p>
<p>I am {props.name}</p>
</div>
);
};
export default UserOutput;
Changes:
1- You are not assigning onChange handler to input element in UserInput component, only passing that handler in props, automatically it will not work.
2- You are updating the value in state in wrong way, it should be name: event.target.value (not string).
Code:
const UserInput = (props) => {
return(
<div>
<input type="text" onChange={props.OnInput}></input>
</div>
);
}
OnInputChange = (event) => {
this.setState({
Username:[
{ name: event.target.value },
],
});
}
Working Code:
class App extends React.Component {
state = {
Username: [{ name: "Jacky" }]
};
OnInputChange = event => {
this.setState({
Username: [{ name: event.target.value }]
});
};
render() {
return (
<div>
<UserInput OnInput={this.OnInputChange} />
<UserOutput name={this.state.Username[0].name} />
</div>
);
}
}
const UserInput = (props) => {
return (
<div>
<input type="text" onChange={props.OnInput} />
</div>
);
};
const UserOutput = props => {
return (
<div>
<p>I am {props.name}</p>
<p>I am {props.name}</p>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='app' />
Your OnInput property is not passed down to your input component. It would have to be:
const UserInput = props => {
return(
<div>
<input type="text" onChange={props.OnInput} />
</div>
);
};
Your handler uses a literal string 'event.target.value', it must read the value:
Username: [{ name: event.target.value }],
Also, there is no need to wrap username in an array and another object, you can just use:
Username: event.target.value,
and access this.state.Username.
and initialize as
state = {
Username: "Jacky"
};
1.) You need to pass the event handler to your UserInput component.
const UserInput = ({ onChange }) => {...}
and then
<UserInput onChange={this.OnInputChange} />
2.) You need to use the passed event handler in your input onChange.
<input onChange={onChange} />
3.) You need to use event.target.value not 'event.target.value'.

clear the material UI text field Value in react

How to clear the materialUI textfield value in react?
Check the below code -
<TextField
hintText=""
ref={(node) => this._toField = node}
onChange={this.changeToText}
floatingLabelText="To*"
floatingLabelFixed={true}
fullWidth={true}
/>
I'm using the raisedButton while pressing it validate the above field. If the field has error then displaying the error message. If not, then we need to clear the input. But how can we clear the input text?
if you are using a stateless functional component then you can use react hooks.
Also make sure you are using inputRef
import React, { useState, useRef } from "react";
let MyFunctional = props => {
let textInput = useRef(null);
return (
<div>
<Button
onClick={() => {
setTimeout(() => {
textInput.current.value = "";
}, 100);
}}
>
Focus TextField
</Button>
<TextField
fullWidth
required
inputRef={textInput}
name="firstName"
type="text"
placeholder="Enter Your First Name"
label="First Name"
/>
</div>
);
};
There is a value property that you have to pass to the TextField component.
check example below:
class SomeComponent extends Component {
state = {value: ''}
resetValue = () => {
this.setState({value: ''});
}
render() {
return (
<div>
<TextField
...
value={this.state.value}
/>
<button onClick={this.resetValue}>Reset</button>
</div>
)
}
}
try this
import { Button, Container, InputBase } from '#material-ui/core'
import React, { useState } from 'react'
const ClearText = ()=> {
const [text , setText] = useState("")
const clearTextField = () => setText("")
return (
<Container>
<InputBase
value={text ? text : ""}
onChange={(e)=>setText(e.target.value)}
/>
<Button onClick={clearTextField} > Clear </Button>
</Container>
)
};
export default ClearText;
You need to, somehow, store the input's value. State seems to be an initial approach in this case. Whenever the text changes, you have to update the state. Same applies when you click the button and click the input's value afterwards:
class App extends React.Component {
constructor() {
super()
this.state = {
value: ''
}
this.handleChange = this.handleChange.bind(this)
this.handleClick = this.handleClick.bind(this)
}
handleChange(event) {
this.setState({ value: event.target.value })
}
handleClick() {
// validation...
this.setState({ value: '' })
}
render() {
return (
<div>
<input type="text" value={this.state.value} onChange={this.handleChange}/>
<button onClick={this.handleClick}>Click-me</button>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
<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="root"></div>

simple Debounce not working in react 16 but works in jsfiddle with react 14.3

This doesn't work in react 16, but this jsfiddle works fine: https://jsfiddle.net/kp04015o/9/
Can any one debug this error why? Cannot read property 'value' of null, at handleChange = debounce(e => this.setState({searchTerm: e.target.value}), 1000);
import React from 'react';
import ReactDOM from 'react-dom';
const debounce = (cb, wait) => {
let timeout;
return function() {
let callback = () => cb.apply(this, arguments);
clearTimeout(timeout);
timeout = setTimeout(callback, wait);
}
}
class Debounce extends React.Component {
state = {
searchTerm: '',
};
handleChange = debounce(e => this.setState({searchTerm: e.target.value}), 1000);
render() {
return (
<div>
<input type="text" onChange={this.handleChange}/>
<div>Search Value 2: {this.state.searchTerm}</div>
</div>
);
}
}
ReactDOM.render(<Debounce />, document.getElementById('root'));
Read about Event Pooling
Here you have a working code:
class Debounce extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
state = {
searchTerm: '',
};
setSearchTerm = debounce((searchTerm) => this.setState({ searchTerm }), 1000);
handleChange(e) {
this.setSearchTerm(e.target.value);
}
render() {
return (
<div>
<input type="text" onChange={this.handleChange} />
<div>Search Value 2: {this.state.searchTerm}</div>
</div>
);
}
}
or nicer with ES7 decorators and decko module:
import { debounce, bind } from 'decko';
class Debounce extends React.Component {
state = {
searchTerm: '',
};
#debounce(1000)
setSearchTerm(searchTerm) {
this.setState({ searchTerm });
}
#bind
handleChange(e) {
this.setSearchTerm(e.target.value);
}
render() {
return (
<div>
<input type="text" onChange={this.handleChange} />
<div>Search Value 2: {this.state.searchTerm}</div>
</div>
);
}
}
I feel like I know this.
Try changing this:
<input type="text" onChange={this.handleChange} />
to either:
<input type="text" onChange={this.handleChange.bind(this)} />
or:
<input type="text" onChange={(e) => this.handleChange(e)} />
That is my gut reaction every time I see something of undefined with a React event, and because your default state is handled. If this works, it's because the execution context or lexical environment is in a different dimension than it might appear.

React Component Not Updating After Changing A Value

In ReactJS, I'm writing a stateless component;
Since I've read avoiding unnecessary states is best practice.
The component represents an input field which executed a function when the input box contains a value.
export const InputField = (props) => {
const InputFieldContentsChanged = (event) => {
props.onChange(event.target.value);
};
return (
<div data-component="input-field"
className={(props.value !== "" ? "value": "")}>
<input type={props.type} value={props.value} onChange={InputFieldContentsChanged} />
<span className="bar"></span>
<label>{props.label}</label>
</div>
);
};
InputField.PropTypes = {
type: PropTypes.oneOf([ "text", "password" ]).isRequired,
label: PropTypes.string.isRequired,
value: PropTypes.string,
onChange: PropTypes.func.isRequired
}
Now,
I've created another component which just is a sample to test the component above.
This looks like the following:
export const SampleComponent = (props) => {
let componentUsername = "";
const onUsernameChanged = (username) => {
componentUsername = username;
};
return (
<InputField type="text" label="Username" value={componentUsername} onChange={onUsernameChanged} />
);
};
So, I'm binding the value to a custom variable in the component which is changed when the contents of the input field does change.
How does it come that the input field component does not update itself with the new username?
Kind regards,
I'm writing a stateless React component since it's best practice to avoid state when not needed.
In your code you are trying to use your own kind of "state" though, and it's just a variable (componentUsername). But since it's not React state, the component does not re-render upon the change of the variable. React simply doesn't know about the change.
So, either use the usual setState instead of re-assigning the your own "state" variable, or put the logic in the parent component and pass the componentUsername to the SampleComponent via props:
const SampleComponent = props => (
<input type="text" onChange={props.onChange} value={props.value} />
);
class ParentComponent extends React.Component {
constructor() {
super();
this.state = { value: '' };
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(e) {
console.log(e.target.value);
this.setState({ value: e.target.value });
}
render() {
return (
<SampleComponent
value={this.state.value}
onChange={this.handleInputChange}
/>
);
}
}
ReactDOM.render(<ParentComponent />, document.getElementById('root'));
<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="root"></div>
The idea of functional components is to not perform any changes to the state or props.
Since there is no trigger to re-render you component you won't see any change.
Change this React.Function to a React.Component.
const InputField = (props) => {
const InputFieldContentsChanged = (event) => {
console.log(event.target.value);
props.onChange(event.target.value);
};
return (
<div data-component="input-field"
className={(props.value !== "" ? "value": "")}>
<input type={props.type} value={props.value} onChange={InputFieldContentsChanged} />
<span className="bar"></span>
<label>{props.label}</label>
</div>
);
};
class SampleComponent extends React.Component {
constructor() {
super();
this.state = { componentUsername : ""};
}
onUsernameChanged = (username) => {
console.log(username);
this.setState({componentUsername: username});
}
render() {
return (
<InputField type="text" label="Username" value={this.state.componentUsername} onChange={this.onUsernameChanged} />
);
}
};
ReactDOM.render(<SampleComponent/>, 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"></div>

React: reset the input value on space pressed

I am new in React. In my react component, I have an input, and i need to reset the value of input to "" when the user press space button.
You can consider the component as following:
import React,{Component} from 'react';
export default class InputReceiver extends Component{
render(){
return(
<div className="col-sm-10">
<input type="text" className="form-control" onChange={this.props.inputHandler}/>
</div>);
}
}
Is it true that, i have to make it in the action?
but the action does not understand the input.
Point:
I should not use jQuery.
Using React Hooks, you can do the following:
Use the onKeyDown attribute on < input /> field to record each key press. Check if the pressed key is a space ( ASCII value 32 in this case ), and reset the input field.
const InputField = () => {
const [inputValue, setInputValue] = React.useState("");
const handleInputChange = (e) => {
setInputValue(e.target.value);
};
const handleSpace= (e) => {
if (e.keyCode === 32) {
setInputValue("");
}
};
return (
<div>
<input
type="text"
value={inputValue}
onChange={handleInputChange}
onKeyDown={handleSpace}
/>
<p>Entered value: {inputValue} </p>
</div>
);
};
Note: KeyboardEvent.keyCode has been deprecated. Instead, use KeyboardEvent.key.
In the above example, it would be:
const handleSpace= (e) => {
if (e.key === " ") {
setInputValue("");
}
};
Use onKeyDown to call a function that detect the pressing of spacebar. If spacebar is pressed fire an action that reset the value of input.
Component
import React,{Component} from 'react';
import * as action from './path/to/action';
class InputReceiver extends Component{
detectSpacePresent = (e) => {
if(e.keyCode == 32) {
this.props.changeInputValue('');
}
}
render(){
return(
<div className="col-sm-10">
<input type="text" className="form-control" value={this.props.inputValue} onChange={this.props.inputHandler} onKeyDown={this.detectSpacePresent}/>
</div>);
}
}
function mapStateToProps(state) {
return {
inputValue: state.inputValue;
}
}
function mapDispatchToProps(dispatch) {
return {
changeInputValue: bindActionCreator(action, dispatch);
}
}
export default connect(mapStateToProps, mapDispatchToProps)(InputReceiver);
Action
export function changeInputValue(val) {
return {type:'CHANGE_INPUT_VALUE', data: val}
}
Reducer
export const = (state = {}, action) {
switch(action.type) {
case 'CHANGE_INPUT_VALUE':
return {inputValue: action.data}
}
}
You really don't need to have redux. People started taking redux for granted. You could simply use a onChange handler in the InputReceiver component and call the inputHandler from it. The example below should explain.
Hope it helps!
class InputReceiver extends React.Component{
constructor(props) {
super(props)
this.state = {
value : ''
}
this.onChange = this.onChange.bind(this)
}
onChange(e){
const val = e.target.value
const lastChar = val[val.length - 1] //take only the last character
if(lastChar === ' ') //check if the last character is a <space>
this.setState({value: ''}) //if yes, reset value
else
this.setState({value: val})//if no, save the value
this.props.inputHandler && this.props.inputHandler(e)
}
render(){
return(
<div className="col-sm-10">
<input type="text" className="form-control" value={this.state.value} onChange={this.onChange}/>
</div>);
}
}
class App extends React.Component{
inputHandler(e){
console.log('called inputHandler')
}
render(){
return <InputReceiver inputHandler={this.inputHandler} />
}
}
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"></div>

Resources