How to pass on a start value to input? [duplicate] - reactjs

This question already has answers here:
React Input Element : Value vs Default Value
(4 answers)
Closed 3 years ago.
Here it is:
<input type="text" name="firstname" onChange={this.handleInputChangeEdit}/>
When I try to set start value into input (value ={...}) it becomes blocked and it's impossible to change string. How to evade this?

You can use defaultValue instead of value as attribute for input as mentioned on react documentation (for uncontrolled components). There are multiple ways to effect the same change but this seems to be the simplest based on what you were already trying to do.
https://reactjs.org/docs/uncontrolled-components.html#default-values

To give the input a default value while still being able to update it, you should connect it to your component-state.
Simply put, any time you type something, you trigger your handleInputChangeEdit function. It takes the text you enter and updates the firstname field in state. That value gets passed back down to the input for display.
class App extends React.Component{
state = {
firstname: "This is the default text"
}
handleInputChangeEdit = (event) => {
this.setState({
[event.target.name]: event.target.value
})
}
render(){
return(
<input
value={this.state.firstname}
type="text"
name="firstname"
onChange={this.handleInputChangeEdit}
/>
)
}
}
The initial/default value will be whatever you had in the state object and now you are free to update the input-text which continues this pattern.

Related

How to limit number of characters in Field using Redux?

I have Field input and my idea is to user can input only 15 characters.
After 15 characters I want not displaying anything in field. I have tried with normalize but not working. I'm checking with value.length and after 15 characters my state is not updating which is good but I can still entering characters. I want after 15 entered characters, if user put something not to show that in browser. Can anyone help me?
<Field
name={`name`}
placeholder='placeholder'
classes={classes}
component={this.component}
onChange={this.changeHandler}
/>
changeHandler= (event) => {
if(event.target.value.length < 16)
{
this.setState({
myProperty: event.target.value
});
}
For redux-form Field there isn't a props to limitate number of chars. Considering that you are using Field in a form, you could validate the field itself (using validate props as in this example) but still the possibility to add more than 15 chars.
But as you know you could customize your Field using component props. Something like:
<Field name="myField" component={renderField}/>
And in renderField you could use input and in input you have maxlength props.
So your renderField could be something like:
const renderField = (field) => (
<div className="input-row">
<input {...field.input} type="text" maxlength="15"/>
</div>
)
This should solve your problem.
For this you would need a handled value. Pass value={this.state.myProperty} to the Field. So if this property is no longer updated after 15 characters, the value of the field won't be updated either.

as am not getting what is the functionality of below code

Can someone explain me below function line by line
handleChange(e) {
let fields = this.state.fields;
fields[e.target.name] = e.target.value;
this.setState({
fields
});
as my understanding
we are creating a variable fields and storing the present state of fields in the variable because we cant mute the state.
i don't have idea about fields[e.target.name] = e.target.value;
updating the fields
can someone explain me the above function line by line?
fields[e.target.name] this syntax is also used to access the Object Properties.
var obj = {name:'abc', color:'red'}
console.log(obj.name) // this print 'abc'
console.log(obj['name']) // also print 'abc'
with obj['xxx'] syntax you can dynamically read and set properties to the object.
reference https://www.w3schools.com/js/js_objects.asp
So in your problem fields variable take existing fields object from the local state. And in each event it create new property with that event target name and add that event target value as that new property value. if that property name already exist within the fields object then it only modified the value of that property.
So as in your list,
is correct. With let fields = this.state.fields; it get previously stored values into the fields variable. without losing previous data
this is what I explained above
your answer is correct. update the state with old and new values
This code let's you dynamically change the value of a field in your component state by using object notation. object[]
By using fields[event.target.name] you're going to look for a field in your component state that matches the name of the element that's causing the event to occur. Then it looks like you're updating the value for that field with event.target.value
Why this is useful
Let's say you have a component where you want to retrieve multiple inputs from a user. Without object notation, you might end up writing very repetitive code like writing a different event handler for each input in order to determine what field to update in your component state:
BAD:
handleOnChange1 = (event) => (this.setState({userName: event.target.value}))
handleOnChange2 = (event) => (this.setState({lastName: event.target.value}))
However, by naming your elements and coordinating them with a matching field in your component state, you won't have to worry about writing additional event handlers as long as you use object notaton.
GOOD:
class UserForm extends React.Component{
state = {
firstName: "",
lastName: ""
}
handleOnChange = (event) => {
this.setState({
[event.target.name]: event.target.value
})
}
render(){
return(
<div>
<input name="firstName" value={this.state.firstName} onChange={this.handleOnChange}/>
<input name="lastName" value={this.state.lastName} onChange={this.handleOnChange}/>
</div>
)
}
}

Dynamically set a property value for an Input in Semantic UI React

I have an Input element that I want to display an error on when the form validation fails.
<Input ref="amount" error={false} />
When the user enters an incorrect amount, I want to change "error" to "true". How can this be done?
I have tried:
this.refs.amount.props.error = true;
Which seems bad but I'm not sure how else. If I add a conditional statement in the definition of the Input element, that seems to only evaluate once and then remain the same. Do I need to force an update on the element? If so, how?
Yes it's possible to validate the input when the form is submitted.
All you need is to keep track on input value and use same approach as #SajithDilshan for the input error.
this.state = {
error: false,
value: ''
}
...
render(){
return
...
<Input
ref="amount"
value={this.state.value}
error={this.state.error}
/>
...
}
Then onSubmit should looks like:
onSubmit(e){
const isError = this.state.value === '';
this.setState({error: isError});
// rest of your logic
}
Hope it will help!
Use the onChange() method on the input as below.
<Input ref="amount" onChange={this.onInputChange} error={this.state.error} />
After that implement the onInputChange() method as below in your component.
onInputChange = (e) => {
if (e.target.value === "") { // logic to validate the input
this.setState({error: true});
} else {
this.setState({error: false});
}
}
Note that this will add error property to the state.
Further, you should not modify the props within a component. Props are passes from parent component to the child component as immutable inputs.
This is not exactly the answer, but still:
This type of fiddling with each possible state of form element (valid, invalid, warning, show tooltip, was edited, in focus, left focus, was submitted, submit failed or not, etc) becomes to much trouble when the form grows beyond 1 input field.
I would suggest to use redux-form package that integrates with semantic-ui-react` almost perfectly and provided you have provided it with the validate function does everything else for you. It takes some time to understand the basics of it, but it really pays.

How to clear the text field in formsy material ui React

Hi I am using React 14 and writing it in ES6. I am using formsy-material-ui for form validations. There is a scenario where I want to clear the value of text field on click of a button.
I tried the following code
<FormsyText
name="email"
ref="email"
validations="isEmail"
validationError="Invalid Email"
hintText="Email"
value={this.state.emailValue}
/>
And on click of the button, I am executing the following line of code
this.setState({emailValue : ''});
But the text field is not getting cleared.
How to clear it.
Pls help.
So, if you were using a controlled input (maybe using directly the TextField from Material-ui) - your code would be right, however the FormsyText component handle it's value internally.
If you pass a value or defaultValue it'll just be used when it's rendered, you can check it here.
I only see one way to clear the value now, in an imperative style.
this.refs.email.setState({ value: "" })
Note: I suggest you to change the way you're using the ref. Using refs with a string is deprecated and probably will be removed in the future. Instead you should pass a function that's gonna receive that component. https://facebook.github.io/react/docs/more-about-refs.html
Example:
<FormsyText
name="email"
ref={(node) => this._emailText = node}
validations="isEmail"
validationError="Invalid Email"
hintText="Email"
value={this.state.emailValue}
/>
//And to clear it
this._emailText.setState({ value: "" })
Try reset field after setState:
this.setState({emailValue : ''});
this.refs.email.reset()
Also you can reset all form.
this.refs.form.reset()
const formRefdeposit = useRef(null);
<Formsy
onValidSubmit={handleSubmit}
onValid={enableButton}
onInvalid={disableButton}
ref={formRef}
>
....Form Fields
</Formsy>
if you have class in your js file then use
this.formRef.current.reset();
if without class then use
formRef.current.reset();

Stop cursor jumping when formatting number in React

I have an input field on my react component that shows the line price for an item (two decimal places with thousands separators). I want the value shown to be in money format when the component first renders and also to be kept in money format as user types in the field.
At the moment I have the following code in my component:
var React = require('react');
import accounting from 'accounting';
MoneyInput = React.createClass({
propTypes: {
name: React.PropTypes.string.isRequired,
onChange: React.PropTypes.func.isRequired,
value: React.PropTypes.number,
error: React.PropTypes.string,
},
onChange(event) {
// get rid of any money formatting
event.target.value = accounting.unformat(event.target.value);
// pass the value on
this.props.onChange(event);
},
getValue() {
return accounting.formatNumber(this.props.value, 2)
},
render() {
return (
<div className="field">
<input type="text"
name={this.props.name}
className="form-control"
value={this.getValue()}
onChange={this.onChange} />
<div className="input">{this.props.error}</div>
</div>
);
}
});
module.exports = MoneyInput;
That code displays the data correctly formatted, but every time I enter a value the cursor jumps to the end of the number.
I understand why that's happening (I think) and I've read several questions here related to not losing cursor position in JavaScript (here and here for example).
My question is what's the best way to deal with this in React?
I think that ideally I wouldn't want to store the cursor position in state (e.g. I would want these to be Presentation Components in Dan Abramov syntax) so is there another way?
An easy solution for losing cursor/caret position in the React's <input /> field that's being formatted is to manage the position yourself:
onChange(event) {
const caret = event.target.selectionStart
const element = event.target
window.requestAnimationFrame(() => {
element.selectionStart = caret
element.selectionEnd = caret
})
// your code
}
The reason your cursor position resets is because React does not know what kinds of changes you are performing (what if you are changing the text completely to something shorter or longer?) and you are now responsible for controlling the caret position.
Example: On one of my input textfields I auto-replace the three dots (...) with an ellipsis. The former is three-characters-long string, while the latter is just one. Although React would know what the end result would look like, it would not know where to put the cursor anymore as there no one definite logical answer.
onKeyUp(ev) {
const cardNumber = "8318 3712 31"
const selectionStart = ev.target.selectionStart; // save the cursor position before cursor jump
this.setState({ cardNumber, }, () => {
ev.target.setSelectionRange(selectionStart, selectionStart); // set the cursor position on setState callback handler
});
}
I think we can do this at a DOM level.
What I did was provided id to the input field.
There is a property selectionEnd in the input element.
What you can do is just get the input element in the normalize function and get its selectionEnd property
const selectionEnd=inputElm &&inputElem.selectionEnd?inputElm.selectionEnd:0;
And since the problem is only while we press the back button. We add a condition as follows
if(result.length<previousValue.length){
inputElm.setSelectionRange(selectionEnd, selectionEnd)
}
But since this value will be set after we return from the function and the returned value will again be set pushing the cursor to the end, we return just add a settimeout.
setTimeout(() => {
if(result.length<previousValue.length){
inputElm.setSelectionRange(selectionEnd, selectionEnd)
}
}, 50);
I just faced this problem today and seems like a timeout of 50 is sufficient.
And if you want to handle the case of user adding the data in the middle. The following code seems to be working good.
if(result.length<previousValue.length){
inputElm.setSelectionRange(selectionEnd, selectionEnd)
} else if(selectionEnd!==result.length){ // result being the computed value
inputElm.setSelectionRange(selectionEnd, selectionEnd)
}
set value(val) { // Set by external method
if(val != this.state.value) {
this.setState({value: val, randKey: this.getKey()});
}
}
getKey() {
return 'input-key' + parseInt(Math.random() * 100000);
}
onBlur(e) {
this.state.value = e.target.value; // Set by user
if(this.props.blur) this.props.blur(e);
}
render() {
return(
<input className="te-input" type="text" defaultValue={this.state.value} onBlur={this.onBlur} key={this.state.randKey} />
)
}
If you need an Input that's both editable without cursor move and may be set from outside as well you should use default value and render the input with different key when the value is changed externally.
I have the same problem and for me it is because I am using Redux.
This article really explained it well.
https://medium.com/#alutom/in-order-to-understand-what-is-really-happening-it-might-be-helpful-to-artificially-increase-the-e64ce17b70a6
The browser is what manages the input curser and when it detects a new text it automatically kicks the curser to the end, my guess is that the state updates the textfield in a way the triggers that browser behaviour.

Resources