React.js cursor focus issue on chrome - javascript

I have a simple react class which renders a controlled input box of type number.
var Form = React.createClass({
getInitialState: function() {
return { value: 12.12 };
},
handleChange: function(e) {
this.setState({ value: e.target.value });
},
render: function() {
return (
<input
onChange = {(e) => this.handleChange(e)}
type = "number"
value = {this.state.value}
/>
);
}
});
ReactDOM.render( <Form /> , document.getElementById('container'));
This code is present in this jsfiddle.
To change the value, when I delete the numbers one by one and delete the decimal point, the focus suddenly shifts to the start of the input box.
This happens on latest Chrome browser (54.0.2840.87) but not on Firefox.
If I use a defaultValue instead of value in state, on Chrome, even when I add a decimal value to the number, the focus shifts to the start. (The issue happens both on adding decimal value or on deleting the decimal part)
Please refer to this jsfiddle.
I saw the answer to a similar question here. But the problem persists in Chrome when I try to delete numbers till decimal point.
Is there a way to get around this problem?
Thanks in advance for your help.

I wanted to use an input box of type 'number' (for stepper, etc.), so did a work around by using refs.
I took this idea of using refs from an answer to a similar question here.
I do not use defaultValue in the input tag but set the initial value in componentDidMount. And on change, I set value in a variable for future use.
var Form = React.createClass({
componentDidMount() {
this.input.value = "123.12";
},
handleChange: function(e) {
this.value = e.target.value;
},
render: function() {
return (
<input
onChange = {(e) => this.handleChange(e)}
type = "number"
ref={(elem) => this.input = elem}
/>
);
}
});
ReactDOM.render( <Form /> , document.getElementById('container'));
Please find jsfiddle code here.

It happens because your type="number". The e.target.value variable will have type of number too. Since there is no number that has value 12. (happens when you delete last decimal number after decimal point), then e.target.value will simply has value of 12, so the value jump from 12.1 to 12 (note that two characters deleted at the same time). It seems that Chrome doesn't like that change and behave strangely.
The solution for this problem is to simply change your input type to text, and validate your text box on submit.
Or simply strip invalid characters on text box change.
var Form = React.createClass({
getInitialState: function() {
return { value: 12.12 };
},
handleChange: function(e) {
this.setState({
value: e.target.value.replace(/([^0-9\.])/g, '')
});
},
render: function() {
return (
<input
onChange = {(e) => this.handleChange(e)}
type = "text"
value = {this.state.value}
/>
);
}
});
ReactDOM.render( <Form /> , document.getElementById('container'));
<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="container"></div>

Related

"Reset" button won't work unless it refreshes page, and gives me an error otherwise (React.JS)

So I'm working in React.JS, and I'm trying to make something like an input field, where a user can enter a number of their choice, and it will show up in the text.
I decided to add a "Reset to zero" button, as an extension.
<div>
Count: {this.state.value}
<form>
<input type="number" value = {this.state.value} onChange = {this.inputChange}/>
<br/>
<button onClick = {this.reset}>reset to zero</button>
</form>
</div>
It works, but it refreshes the page every time it does so.
I read online, and I decided to add "type=button" to my button as so:
<button type="button" onClick = {this.reset}>reset to zero</button>
When I run my code again, it still increments fine, but when I click the button, nothing happens, and when I try to increment it again, I get an error, "TypeError: this.setState is not a function".
The error is coming from this method:
inputChange = event => {
this.setState ({value: event.target.value})
}
I know where the error is coming from, but I don't know why it happened, or how to fix it (note that I'm also a beginner at JavaScript and React.JS)
I hope someone can help me.
Here's my code in entirety, for reference.
class Slider extends React.Component {
constructor(props){
super(props);
this.state = {
value: 0
}
}
inputChange = event => {
this.setState ({value: event.target.value})
}
reset = () => {
this.setState = ({
count: 0
})
}
render() {
return (
<div>
Count: {this.state.value}
<form>
<input type="number" value = {this.state.value} onChange = {this.inputChange}/>
<br/>
<button type = "button"onClick = {this.reset}>reset to zero</button>
</form>
</div>
);
}
}
Thank you guys, in advance.
The reason nothing happens on reset and you are getting that error on input change, is that you are reassigning this.setState in your reset function rather than calling it. Also, you are setting count instead of value, which would lead to the wrong state being set.
This is what your reset function should be:
reset = () => {
this.setState ({
value: 0
})
}
When you call this.setState, React will trigger a re-render in your component with the new state.
That is currently not happening when you click reset. On your subsequent call to inputChange, this.setState has been reassigned with an object, and is no longer callable, throwing that error.
Try replacing your button like this:
<button type = "button"onClick = {this.reset.bind(this)}>reset to zero</button>
This will force the method to execute being this the scope.

Focusing input field with Mousetrap.js - but input field also pastes the hotkey as value?

Have a look at the following example. I have enhanced the official example here with some Mousetrap functionality. So whenever somebody presses alt+1, the first input field will focus, whenever somebody presses alt+2 the second input field will be focused. It works.
Problem:
However, the input field then also takes the value of whatever was pressed as the hotkey (alt+1 then renders to ¡, alt+2 renders to € in the input). But I just want this to be a hotkey, I don't want it's actual value in the input field. How do I do this?
I could clear / delete the input field completely. This would work in the example here, but I don't want to do it since in my final app the state of the input field will need to be preserved, so I cannot just delete it.
Any advice?
import React from "react"
import Mousetrap from "mousetrap"
export default class CustomTextInput extends React.Component {
constructor(props) {
super(props)
// create a ref to store the textInput DOM element
this.textInput = React.createRef()
this.textInput2 = React.createRef()
this.focusTextInput = this.focusTextInput.bind(this)
}
componentDidMount() {
Mousetrap.bind("alt+1", () => {
this.focusTextInput(1)
})
Mousetrap.bind("alt+2", () => {
this.focusTextInput(2)
})
}
focusTextInput(id) {
// Explicitly focus the text input using the raw DOM API
// Note: we're accessing "current" to get the DOM node
if (id === 1) {
this.textInput.current.focus()
}
if (id === 2) {
this.textInput2.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} className="mousetrap" />
<input type="text" ref={this.textInput2} className="mousetrap" />
</div>
)
}
}
I
have you tried event.preventDefault() ?
Mousetrap.bind("alt+1", (e) => {
e.preventDefault();
this.focusTextInput(1);
})
Mousetrap.bind("alt+2", () => {
e.preventDefault();
this.focusTextInput(2)
})
#Dhananjai Pai solution didn't worked for me in the same case.
I know this is very old question, so I will just leave the solution, that worked for me, just if someone needs it.
<input
type="text"
placeholder="Put focus here"
name="something"
id="order-code"
class="form-control barcodeScanner"
>
if (typeof Mousetrap !== 'undefined') {
Mousetrap.bind(['`', '('], function (e) {
e.preventDefault();
$('.barcodeScanner').focus()
}, 'keyup');
}
Adding as third option the 'keyup' event solved the issue with typing inside the input.
Source:
https://craig.is/killing/mice#api.bind
There is a third argument you can use to specify the type of event to listen for. It can be keypress, keydown or keyup.
It is recommended that you leave this argument out if you are unsure. Mousetrap will look at the keys you are binding and determine whether it should default to keypress or keydown.

How to edit an element's text with React.js?

i wanna edit my p element's text when i press edit button.
When i click edit button, i display a textarea and get keyed text with alert but can't put that text to my p element.
What is the simple way to do it with React.js ?
JSFIDDLE
When i press edit button, editing state changing and textarea shows up.The code below.
renderNormal: function() {
return (
<div>
<p>Edit me</p>
<button onClick={this.edit}>Edit</button>
</div>
)
},
renderForm: function() {
return (
<div>
<textarea ref="newText" defaultValue="Edit me"></textarea>
<button onClick={this.save}>Save</button>
</div>
)
},
render: function() {
if (this.state.editing) {
return this.renderForm()
} else {
return this.renderNormal()
}
}
You need to store and retrieve the text from a state variable. Modifying the state causes a re-render, which will then display the updated text. Copied from your JSFiddle... note where I've added a "text" property to your state
var MyCom = React.createClass({
getInitialState: function() {
return {
editing: false,
// ** Initialize "text" property with empty string here
text: ''
}
},
edit: function() {
this.setState({
editing: true
})
},
save: function() {
var val = this.refs.newText.value;
alert(val)
this.setState({
// ** Update "text" property with new value (this fires render() again)
text: val,
editing: false
})
},
renderNormal: function() {
// ** Render "state.text" inside your <p> whether its empty or not...
return (
<div>
<p>{this.state.text}</p>
<button onClick={this.edit}>Edit</button>
</div>
)
},
renderForm: function() {
return (
<div>
<textarea ref="newText" defaultValue="Edit me"></textarea>
<button onClick={this.save}>Save</button>
</div>
)
},
render: function() {
if (this.state.editing) {
return this.renderForm()
} else {
return this.renderNormal()
}
}
})
ReactDOM.render(
<div>
<MyCom/>
<MyCom/>
</div>,
document.querySelector(".box")
)
You have to set a value on the state on the button is clicked, and then read that on render.
Example:
handler : function () {
this.setState({ value : 'hey' });
},
render : function () {
return <p>{ this.state && this.state.value ? this.state.value : 'hoy' }</p>;
}
Everytime you want the render method to change according to something that can happen, the action that triggers it must trigger a state change, and change the state object, and the object will be rerendered, so the render method should check the current state.
If you want to change the value of a input (or in your case, a textarea), you can use the linkedstate pattern as a two way databinding (more here).
I particularly use this lib. There are plenty of examples there.
I actually had this same problem, here was my solution:
{editableSubTasks.filter(id => id === subTask.Id).length > 0 ? <input type="text" /> : <span>{subTask.Name}</span>}
So basically, you have an array, in my case it was editableSubTasks. Whenever I would trigger the text element to change to a textarea, I would simply add that guy to the edtiableSubTasks array. And then in my map function, if the Id of the correspnding item was in the editableSubTasks array, I would use a ternary operator to tell it to be a <input type="text">, otherwise just a span. In your case obviously you can use a textarea. This worked out wonderfully. Here was my SO with the answer that I ended up using:
How to dynamically show/hide a list of items in react
If you don't need the array, then the answer is even simpler, just have a bool and change it to true when you want it to be a text area.

react js , get siblings or parent value

I'm new to react, I'm curious how to do this properly.
suppose I have this form, by clicking button, I want to get textbox value,
var form = React.createClass({
submit : function(e){
//how to get textbox value?
},
render : function(){
return (
<form>
<input type="text" id="textbox" value="hey, get me"/>
<button onClick={this.submit}>Get it</button>
</form>
);
}
});
Any answer will be appreciated! thank you!
React enforces parent-to-child unidirectional data flow.
So, there's no simple way to access data from siblings.
But, if a child changes the state across the component, you probably want a state for keeping a track of that.
Sample code:
var FormBox = React.createClass({
getInitialState: function () {
return {
textBox: 'hey, get me!'
}
},
pressButton: function () {
alert(this.state.textBox)
},
textChange: function (e) {
this.setState({
textBox: e.target.value
})
},
render: function () {
return (
<form action='.'>
<input type='text' placeholder={this.state.textBox} onChange={this.textChange}/>
<button onClick={this.pressButton}> Get it </button>
</form>
)
}
})
ReactDOM.render(<FormBox />, document.getElementById('root'))
JSBin demo: https://jsbin.com/koxujuwope/edit?js,output
Also, just a suggestion... You should move to ES2015
One way to accomplish this is using refs.
After building your component, you may find yourself wanting to "reach
out" and invoke methods on component instances returned from render(). link to refs docs
Refs are basically the html elements / react instances you want to access. In this case, we want to get Input html element. We get input element by this.inputValue. Then read its value by usual js rule.
var form = React.createClass({
submit : function(e){
e.preventDefault();
console.log(this.inputValue.value);
},
render : function(){
return (
<form onSubmit={this.submit}>
<input type="text" id="textbox" defaultValue="hey, get me"
ref={ function(node){ this.inputValue = node }.bind(this) }
/>
<button onClick={this.submit}>Get it</button>
</form>
);
}
});
here is a jsfiddle for your example, you can check the console for the input value.
Another way to accomplish the same thing is to make your input a controlled element. That means you assign input's value attribute to this.state.inputValue and you pass a onChange event handler as onChange={yourInputHandlerFunction}.
See the answer which explains this way of accomplishing the same thing.
The following code helps me to setup communication between two siblings. The setup is done in their parent during render() and componentDidMount() calls.
It is based on https://reactjs.org/docs/refs-and-the-dom.html
class App extends React.Component<IAppProps, IAppState> {
private _navigationPanel: NavigationPanel;
private _mapPanel: MapPanel;
constructor() {
super();
this.state = {};
}
// `componentDidMount()` is called by ReactJS after `render()`
componentDidMount() {
// Pass _mapPanel to _navigationPanel
// It will allow _navigationPanel to call _mapPanel directly
this._navigationPanel.setMapPanel(this._mapPanel);
}
render() {
return (
<div id="appDiv" style={divStyle}>
// `ref=` helps to get reference to a child during rendering
<NavigationPanel ref={(child) => { this._navigationPanel = child; }} />
<MapPanel ref={(child) => { this._mapPanel = child; }} />
</div>
);
}
}

REACT -- How to change the click state of a focused / blurred event

I'm trying to switch between a focused / blurred state for a search bar. Right now the tag has a click handler that shows an input field if the element is clicked. I'm trying to reverse this effect and hide the visibility of the input field when the user clicks outside the element.
My code is:
var Search = React.createClass({
getInitialState:function(){
return{ inputVisible:false }
},
showInput:function(){
this.setState({ inputVisible:true });
},
componentDidUpdate:function(){
if( this.state.inputVisible ){
this.getDOMNode().focus();
}
},
renderInput: function(){
return (
<input type="text" style={this.props} />
);
},
renderLink: function(){
return (
<a><h3 onClick={this.showInput}>Search</h3></a>
);
},
render: function() {
if( this.state.inputVisible ){
return this.renderInput();
}else{
return this.renderLink();
}
}
});
I've tried adding logic to the componentDidUpdate function, so that
if (input.state.isVisible == false ) {
this.getDOMNode().blur();
}
I've also tried adding an onBlur handler to the element and tried creating a hideInput method:
hideInput: function() {
this.setState({ inputVisible:false });
}
and adding to the element:
<a><h3 onClick={this.showInput} onBlur={this.hideInput}>Search</h3></a>
But something just isn't working. Can anyone point out what I'm doing wrong?
You can't focus an H3 element without a tabindex attribute, and so it can't be "blurred" to begin with, thus the onBlur event doesn't fire. Try attaching the onBlur event on the rendered input element in your renderInput method.
Here's an example: http://plnkr.co/edit/STMPIkIQEIAZPZQ9SCq4?p=preview

Categories