I have 2 inputs the first one has setState like
<input onChange={e => this.setState({ price: e.target.value })} />
and the second one I do
<input value={this.state.price} />
This will do binding. Updating the first one will update the second one. But I want to modify the second one without dependent on the first one. I did find one solution; to use defaultValue instead of value. But the problem is input one no longer updates input two on onKeyPress events.
Related
I want to change the value of 3 input text at the same time.
The strange behaviour comes when I try to change the first input field (all of them are changed), then I change the second input field, again I would expect all of them changed, yet you can see the first one won't change.
It is like only "pristine" input fields will change.
https://stackblitz.com/edit/saavz2?file=my-element.js
Change from
<input type="text" data-id=${item.id} value=${this.state[item.id].value ?? ""} #input=${this.onInput} />
to
<input type="text" data-id=${item.id} .value=${this.state[item.id].value ?? ""} #input=${this.onInput} />
See the docs for Property binding.
I am trying to make one login form in react .but I am getting this error
React does not recognize the handleChange prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase handlechange instead.
input value is also not setting input field when I type in input field it is not updating the state why ?
here is my code
https://codesandbox.io/s/quirky-clarke-qbkjw
<form noValidate>
<TextBox
label="Username"
name="username"
type="text"
helperText="Assistive text"
handleChange={handleChange}
handleMouseDownPassword={handleMouseDownPassword}
value={userId}
/>
<TextBox
label="Password"
name="password"
type="password"
helperText="Assistive text"
value={password}
showPassword={showPassword}
handleChange={handleChange}
handleClickShowPassword={handleClickShowPassword}
handleMouseDownPassword={handleMouseDownPassword}
/>
<div className="button-group">
<button>LOGIN</button>
</div>
</form>
In the TextBox component you're passing all the props from the parent via {...props}. Considering that TextField itself doesn't have handleChange property, I assume it passes it down to the underlying input DOM element, which doesn't recognise that prop.
What you can do is to extract the props used inside TextBox and collect the rest using the rest argument, so you don't end up passing unnecessary props down:
export default function TextBox({handleChange, handleClickShowPassword, handleMouseDownPassword, value, ...props}) {
Another option is to remove {...props} from the TextField component and explicitly pass all the necessary props.
Updated Sandbox
React doesn't like uppercase letters in the prop names. Instead of passing "handleChange", pass "handlechange". You will get a similar error for "handleMouseDownPassword".
Regarding the input issue, I don't think you've provided enough context. But you have to have a handleChange method to update the state each time the field is changed.
I changed the handleChange() function, you were only setting the VALUE state, you need to set the state userId when you write on the first input, and the password when you write to the second input
At b.js add props name={stateName} so the handleChange() can know which input is controlling
Check Demo for more:
https://codesandbox.io/s/gracious-heisenberg-z4q4z
(other answeres explained why you are getting that error in console ...props)
I've got a field for a product that its quantity is dependant on another product's quantity (cant be less than 70%, or more than 100%). Thing is, it evaluates it so quiclky that if the main field is '100', I cant enter 75 on the other field, because I first need to enter the '7', and my code considers it less than 70% and instantly changes it to the 70% value.
I've already tried using a self-made 'sleep' function, that makes a promise take some time to resolve.
setInterval and setTimeout also do not work as I intend for some reason (only evaluates the dependent field when I press enter, and it is not after the stablished time). This is not consistent with the rest of the table, so it is not a suitable solution.
This is the angular bit that controls this input
<div class="input-field">
<input class="input" type="number" [integerInput] ="true"
[disabled] ="item.deshabilitado( ) || !editable"
[(ngModel)] ="item.cantidad"
[ngModelOptions]="{standalone: true}"
(keyup) ="setCantidad( item, $event.target.value )"
max="9999" min="1" value="1" >
</div>
Sadly I cant get a minimal and working example. I need the dependent field to be able to evaluate its value automatically (without pressing enter or clicking on another field) without automatically correcting my input when I press only one character.
Use blur() method instead of keyup(). I guess you are validating the input with keyup() and each time you enter value it validates. For instance you are trying to enter 70 but when you enter first character, 7 it is invalid. The blur() fires your method and validates your input when you are done with inputting value.
<div class="input-field">
<input class="input" type="number" [integerInput]="true"
[disabled]="item.deshabilitado( ) || !editable"
[(ngModel)]="item.cantidad"
[ngModelOptions]="{standalone: true}"
(focusout)="setCantidad( item, $event.target.value )"
max="9999" min="1" value="1" >
</div>
In addition, you can use keyup.enter if a user is done with inputting value and presses enter. The value updates when the enter key is pressed or clicked somewhere else.
UPDATE:
I was able to solve this and get it to work like I intended at the beginning. The resulting code for the field I tried to validate would be
debounce (afterValueChanged)="setCantidad( item )"
It behaves in a way that does not need me to click outside the field for it to start validating, instead of the (blur) or (focusout)
Try to use the debounce function
Import debounceTime from rxjs and use it to add some delay :)
Check out this example
In the other field where you are trying to enter 75, you can add an ngModelOptions configuration to update only on blur.
[ngModelOptions]="{ updateOn: 'blur' }"
By default it updates on 'change', which explains the current behavior.
Update
You could also debounce the input using RXJS. This is probably closer to what you were trying to do with setInterval / setTimeout. This is also a use case where Reactive Forms really shines over Template Driven Forms imo, since you'll need to use RXJS operators.
For reactive driven forms, you just pipe an operator before subscribing to the valueChanges observable of the formControl
this.myInput.valueChanges
.pipe(
debounceTime(1000), // add 1 second of delay
distinctUntilChanged() // optional but recommended - only trigger for new values
)
.subscribe(val=> {
console.log('value', val);
});
It is possible to accomplish the same behavior in template driven forms but there is some setup involved. See this SO question/answer
As per the information given, you might want to debounce your function call.
Debounced functions do not execute when invoked, they wait for a pause of invocations over a configurable duration before executing; each new invocation restarts the timer.
<div class="input-field">
<input class="input" type="number" [integerInput] ="true"
[disabled] ="item.deshabilitado( ) || !editable"
[ngModel] ="item.cantidad"
[ngModelOptions]="{standalone: true}"
(keyup) ="setCantidad( item, $event.target.value )"
max="9999" min="1" value="1" >
</div>
In your component class:
timer;
setCantidad(item,value){
if(this.timer){
clearTimeout(this.timer);
}
this.timer = setTimeout(() => {
this.item.cantidad = value;
//perform any operations here
console.log(item, value);
},1000);
}
This will wait for the user to stop typing and execute the operation after the specified time in the timeout.
Note: One additional change, if you want to render the value in the same input field where you are typing, consider changing the [(ngModel)] -> [ngModel].
This will just perform a property binding and not event binding.
Demo stackblitz link : https://stackblitz.com/edit/angular-cu9gss
I have implemented in React a webpage with 3 input fields, each one with the properties of
onChange={this.handleChange} and disabled={this.isDisabled()}
The desired behavior is that when an input field contains 2 digits, the focus will be moved to the next input field.
As long as the field doesn't contain 2 digits, the fields next to must be disabled.
What actually happens, when I type the second digit in the first field, it runs the handleChange function, that function checks whether the field contains 2 digits, find out that yes, and moves the focus to the next input field.
But the next field is disabled! (because the isDisabled function didn't run yet!)
So the cursor doesn't move..
I want to change the order of the happenings, or any other way to solve it.
Do you have any suggestions?
The problem is that this.isDisabled() runs immediately in render but this.handleChange runs on click and most possibly doesn't change the state thus no rerender.
You sholdn't run function on next input, you should pass true or false to its disabled prop. Just make handleChange update the state which defines which fields are disabled. And pass that state to your inputs accordingly.
I had faced the same issue a few days back. My approach was however using react states and focusing the input by its id, that was fetched from state;
So first we make a input - id map for our convenience. And use document.getElementById(this.state.active).focus() function. We change our state via our change handler.
render() {
this.setInputFocus();
return (
<div className="App">
<input id="1" onChange={this.onChange} />
<input id="2" onChange={this.onChange} />
<input id="3" onChange={this.onChange} />
</div>
);
}
setInputFocus = () => {
if (document.getElementById(this.state.active)) {
document.getElementById(this.state.active).focus();
}
};
onChange = e => {
if (e.target.value.length === 2) {
this.setState({ active: this.state.active + 1 });
}
};
Here is a full code that somewhat solves the issue
I wrote a demo below for the test React controlled component input feature. But It seems there is a bug.
class TestComponent extends React.Component{
constructor() {
super();
this.state = {value: 'beef'};
this.handleValueChange = this.handleValueChange.bind(this);
}
handleValueChange(e) {
this.setState({value: e.target.value});
}
render() {
return <div>
<div><input type='text' value={'hello world'} onChange={this.handleValueChange}/></div>
<div><input type='text' value={''} onChange={this.handleValueChange}/></div>
<div><input type='text' value={this.state.value} onChange={this.handleValueChange}/></div>
<div><input type='text' value={null} onChange={this.handleValueChange}/></div>
<div><input type='text' value={undefined} onChange={this.handleValueChange}/></div>
<hr/>
<div><input type='text' defaultValue={this.state.value} onChange={this.handleValueChange}/></div>
<p>{this.state.value}</p>
</div>
}
}
ReactDOM.render(
<TestComponent />,
document.body
)
<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>
The first one input with specifying string value property. when I type something, call handleValueChange function, and the result is hello world + your type thing's first character.
The second one input with empty string value property. when I type something, it calls handleValueChange function, but finally, it always gives me one character.
It's weird.
updated!
I add a input with defaultValue, compare with value={this.state.value}, my head is mess up..
As mentioned in a comment below your question: remove value={''} since this will empty the input everytime it's rendered.
From the react docs, the correct way to do it is
return <div>
<input type='text' value={this.state.value} onChange={this.handleValueChange}/>
<p>{this.state.value}</p>
</div>
This way whenever you type something in the input-area, you'll update the value set in state.
If you want to render the component with a value set in state, you could use:
getInitialState() {
return { value: 'Your default value'}
}
Or, as already suggested, use defaultValue.
Read more here: https://facebook.github.io/react/docs/forms.html
Update:
According to your updated question, I think you'll have to understand what setting a value during render function actually does. Whenever you set a value during render function, you'll "lock" the input field to be that specific value. Meaning the user input will have no effect on the rendered element. From the docs: "User input will have no effect on the rendered element because React has declared the value".
To solve this problem, you'll have to set the value to be something you can change dynamically, in your case that will be value or this.state.value. Like you've done in your third example:
<input type='text' value={this.state.value} onChange={this.handleValueChange}/>
This way React accept the value provided by the user input and will then update the value of the component thereafter.
I still think the docs specifies this pretty clearly, and I think you should read the provided documentation in my original answer.
Update 2
To clearify the part with controlled and uncontrolled components little bit:
A controlled component is a component that has a value property assigned, and will reflect the value from the user input (the value prop).
While an uncontrolled component does not have any value property assigned, and will NOT reflect the value from the user input (since it does not provide any value prop). But if you want to instantiate an uncontrolled component with a value, you should use defaultValue.
In your case (since you try to use a CONTROLLED component) this means that you should NOT use defaultValue, and stick with a correct implementation of a controlled component. That is an implementation using value={this.state.value}.
Again I recommend reading the docs provided. It's actually not that difficult if you manage to understand the docs.
Hope this clearifies some of you problems! :)
use defaultValue instead of value
render() {
return <div>
<div><input type='text' defaultValue={'hello world'} onChange={this.handleValueChange}/></div>
<div><input type='text' defaultValue={''} onChange={this.handleValueChange}/></div>
<div><input type='text' defaultValue={this.state.value} onChange={this.handleValueChange}/></div>
<div><input type='text' defaultValue={null} onChange={this.handleValueChange}/></div>
<div><input type='text' defaultValue={undefined} onChange={this.handleValueChange}/></div>
<p>{this.state.value}</p>
</div>
}
}
The only correct controlled component here is:
<input type='text' value={this.state.value} onChange={this.handleValueChange}/>
The others are not controlled. However, because the others are calling setState and changing the value too, they are affecting the third input.
See what happens:
First input will call setState with e.target.value = hello world + first character you typed. So that will be the new value of the third input
Second input will call setState with only one character since the value of that input is always ''. So one character will be the new value of the third input
Fourth input the same as the second one
Last input, since the value is set to undefined... That is the same as if you don't define any value there, so the fourth input will not be controlled but every time you type it's copying it's actual value to the third input
Conclusion:
To get a controlled input, always set the value to something you control it's change (state or props).
Be careful when changing the same part of the state using different inputs... It becomes really complicated to reason about.