React text form fields without onChange - javascript

Is there any way (please provide an example) in React / React Native to have a component render a timer with milliseconds, a submit button, and a text input field where the following conditions are met?
The user can type in the input field and see what he is typing.
No event handlers are assigned to the input field
When the submit button is clicked the program displays an alert() with the text typed by the user.
The component has an initial state value that is initially displayed in the input field.
The user does not experience unexpected behaviors while typing.
A previous question about this subject lead me to this more specific question about the matter (I hope you can see how it is related).
The most commonly accepted pattern in React to implement input fields suggest to always use an onChange event (see the docs), but I think this leads to repetition and noise in the code, so I´m looking for a better pattern where the developer doesn´t have to think about the onChange behavior when all he needs is an input form field.
Extra Note 1: An "state value" is a value in the component's state. i.e. "constructor(){ this.state = {value:'Initial Value'} };".
Extra Note 2: The purpose of the timer is to make sure you're triggering a render() periodically, which makes it a challenge to display the initial "state value", and allow the user to type normally without an onChange handler to update the state accordingly.

What are you looking for is called Uncontrolled Components.
Take a look here: https://reactjs.org/docs/uncontrolled-components.html

Your conditions will be met with this refs-based pattern ?
class App extends React.Component {
constructor(props) {
super(props);
this.textInput = null;
}
handleSubmit = () => alert(this.textInput.getDOMNode().value);
render() {
return (
<div>
<textarea
ref={el => this.textInput = el}
>
My initial value
</textarea>
<button onClick={this.handleSubmit}type="button">Submit</button>
</div>
);
}
}
React.render(<App />, document.getElementById('app'));
<div id="app"></div>
Working codepen: https://codepen.io/anon/pen/roypOx
Because conditions are about only input field and not timers I've not included a timer in the example.

Related

React Admin - How to disable validation onChange

I'm using react-admin, and I have a huge form, with a bunch of custom validation. It's very slow, even with the build version.
I tried to find a way to disable the validation on change and to have it only on blur or submit. But I have not found a solution or even workaround.
Every time a key is pressed in one of my input text (for example), the validation is triggered multiple times, and it takes a while for the letter to appear.
That's why I want to disable the validation on change.
Here's an example of one of my forms, every letter I write in one of my FormTab, the "validate me" is showing.
export const ThemeCreate: FC = (props: any) => (
<Create {...props} title="ui.themes.create" mutationMode="pessimistic">
<TabbedForm
toolbar={<GenericCreateToolbar />}
validateOnBlur
warnWhenUnsavedChanges
validate={() => {
console.log('validate me!');
}}
>
<MainFormTab />
<TranslationsFormTab />
</TabbedForm>
</Create>
);
You need to use the validateOnBlur={true} prop in the form component.
This prop is from final-form's <Form> component, see the last one in this doc page https://final-form.org/docs/react-final-form/types/FormProps

Updating state in Reactjs?

I am trying to update my state in ReactJS. To do this I have an input field in a Reactjs class. The field is automatically filled in with data from a parent class. The field looks like this:
<input
onChange={e => this.props.store.addLego(e)}
name="piece"
value={this.props.row.original.piece}
/>
The addLego function is designed to update my state and is in a MobX store. It looks like this:
addLego = action("addLego", e => {
this[e.target.name] = e.target.value;
});
However, I can't actually edit the input field! Nothing changes in the field when I type! Thanks for your help!
If you set a value attribute to an <input> field that field becomes a controlled input. This means that whatever gets passed to value is rendered on the screen. In your case, if you are not updating this.props.row.original.piece the <input> field will never get a new value. I'll suggest to read this bit of React's documentation https://reactjs.org/docs/forms.html#controlled-components
It is basically suggesting to keep the new value somewhere (in the component's state for example) and set it back as a value to the field.
Follow this tutorial here will solve your problem. It's a good read too for handling single or multiple inputs
Basically, you'll need a state in the constructor
this.state = {value: ''};
Event handler to set the value every onchange
handleChange(event) {
this.setState({value: event.target.value});
}
And the setup for input
<input type="text" value={this.state.value} onChange={this.handleChange} />

React Input with disabled

I have an input with the disabled boolean propagated from the props. I've found that with that disabled variable being set, even when it's true I cannot type into the input. I can, however, type into the input if I hold the mouse down on it and keep it down as I type.
This happens when I render the component as both controlled and uncontrolled.
The only way to fix it is to either removing disabled or setting disabled={false} -- but I need it to be variabled.
This is my input:
class DashboardWidgetTitle extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.state.title = props.widget.getTitle();
}
render () {
return <input className="title"
value={this.state.title}
disabled={!this.props.isEditMode}
onChange={this._onInputChange.bind(this)}/>
}
_onInputChange(e) {
logit("input change");
this.setState({title: e.target.value});
}
}
Thanks!
EDIT: Extra info --
This is used in a widget within an implementation of ReactGridLayout.
The component is rendered by a widget that is rendered by the implementation of react grid layout, the "dashboard". That Dashboard has isEditMode as a state that's changed externally via a toggle in Angular (we use React within Angular).
If I switch tabs and come back, the focus remains. Otherwise whenever I type a letter, the input becomes unfocused.
The input isn't disabled when it shouldn't be, it just has focusing issues -- however removing the disabled attribute or setting it as a static variable, the issue doesn't remain.
When I switch the disabled toggle to be isEditMode rather than !isEditMode, everything works. It seems to be there's an onclick on the draggable/resizable portion of the ReactGridLayout that's causing some issues.
My issue was described right here: https://github.com/STRML/react-grid-layout/issues/615
My own fault of poor research.

My child component performs validation, but I need to use that validation in a higher component

Let's I have a form where I allow the user to fill in and choose some options.
It might look like
<MyForm>
<InputWithValidation />
</MyForm>
The component <InputWithValidation /> performs some validation, say their username has to be a certain length, before this submission can go through.
Right now the way I have this set-up is MyForm has a function, submit() which I pass as a prop to my InputWithValidation. On clicking submit, InputWithValidation checks its input, and if its valid, will call this.props.submit. It is working fine. However, now I want to add a hotkey to submit the form, so I add the following to MyForm:
document.onkeyup = function (event) {
if (/* keys match what I want */) {
this.submit();
}
}
However, this won't work, as I've never called the validation on the input. How do I solve this issue for 1 input, and for many inputs? While this is similar to form validation I think the hotkey adds a little more complexity.
I feel my question is similar to this question Validate the child's component data in parent component but I am hoping for someone to answer with some sort of best practices for a situation such as this.
Thank you for any help!
Since your <InputWithValidation /> class already has access to the appropriate context of this.props.submit(), I recommend moving that event handler to your <InputWithValidation /> class. You can add it after component mount like this.
class InputWithValidation extends React.Component {
//constructor
//other functions
componentDidMount() {
//add keydown event handler here
//pass to parent with this.props.submit(e.whatever)
}
render() {
//render function
}
}

What is the purpose of passing props to a React search bar?

I'm learning to Think in React, but don't understand why the SearchBar in the example needs to have value={this.props.filterText} and checked={this.props.inStockOnly}, the jsFiddle still works without them and it doesn't make sense for props to be passed to the SearchBar as the Search is the one handling user input and making changes to the state. The user input will be reflected in the value of the input without it being set to this.props.filterText so why is it there?
var SearchBar = React.createClass({
handleChange: function() {
this.props.onUserInput(
this.refs.filterTextInput.value,
this.refs.inStockOnlyInput.checked
);
},
render: function() {
return (
<form>
<input
type="text"
placeholder="Search..."
value={this.props.filterText}
ref="filterTextInput"
onChange={this.handleChange}
/>
<p>
<input
type="checkbox"
checked={this.props.inStockOnly}
ref="inStockOnlyInput"
onChange={this.handleChange}
/>
{' '}
Only show products in stock
</p>
</form>
);
}
});
React has concept of controlled components. A controlled component means its value is set by state (And not the other way around i.e. State being set by value of component).
Consider the following example:
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = {term : ''};
}
render() {
return (
<div>
<input value={this.state.term} onChange = {event => this.setState({term : event.target.value}) }/>
</div>
);
}
}
In above example <SearchBar /> is a Controlled Component.
Following will be sequence of events:
You type 'abc' in input field.
At this time value of input field does not change. Rather the State of component is changing because of our code in onChange Event.
As the state of component changes, the component is rendered again. And now the value of component becomes 'abc'.
This concept becomes more important when we use redux, Actions etc.
Because you will be needing the inputted value from the search bar to the upper component. For instance, if you need to filter a collection based on the given value (through search bar), then the filtering will happen on the upper component, not on the search bar. Search bar is only for the input. We put the value of the search bar from the props to make sure that the values are aligned.
The example here depicts the use of controlled input from the parent component. As you see
<input
type="text"
placeholder="Search..."
value={this.props.filterText}
ref="filterTextInput"
onChange={this.handleChange}
/>
Here the value of input box is set to {this.props.value} and in the handlechange function you are the onUserInput function which you check is again passed as a prop to the Searchbar. This calls the handleUserInput function ni the FilterableProductTable component and it sets the states filterText, inStockOnly and only these are passed as props to the Searchbar component. So although you can do without it, but controlled input is the way to go in most cases since we are accepting the value provided by the user and updating the value prop of the <input> component. This pattern makes it easy to implement interfaces that respond to or validate user interactions. i.e. if you want to validate an input field or put restrictions on the input value its easier to do with controlled input

Categories

Resources