How to correctly pass props to a custom component with Redux-form v6 - forms

I am trying to update my form to redux-form v6.7 and I'm having difficulties wrapping my head about this part.
Say I want to render a select component like so :
<div className="col-md-12">
<Field name="name" component={renderSelect}/>
</div>
Here is my component that was working fine with the previous versions of react-redux, obviously with a form prop named "name" :
<VirtualizedSelect
{...domOnlyProps(name)}
filterOptions={itemsFilter}
options={this.state.items.items}
onChange={name.onChange}
value={name.value}
name="name"
placeholder="Name"
onBlur={() => name.onBlur(name.value)}
autoBlur={true}
simpleValue={true}
multi={true}
clearable={false}
onBlurResetsInput={false}
onCloseResetsInput={false}
delimiter="|"
showNewOptionAtTop={false}
selectComponent={Creatable}
promptTextCreator={(label) => {return "Search for " + label}}
/>
So now I am trying to wrap this component in a renderSelect() function. But I am unsure how to correctly pass the props I need to the custom component. What props should I pass, which props are passed by default, etc.
const renderSelect = ({/*what to pass here?*/ input }) => (
<FormGroup controlId="name" role="form" className="col-md-12">
<div className="group selectW" style={{width: '100%'}}>
<VirtualizedSelect
{...domOnlyProps(name)}
filterOptions={itemsFilter}
options={this.state.items.items}
onChange={name.onChange}
value={name.value}
name="name"
placeholder="Name"
onBlur={() => name.onBlur(name.value)}
autoBlur={true}
simpleValue={true}
multi={true}
clearable={false}
onBlurResetsInput={false}
onCloseResetsInput={false}
delimiter="|"
showNewOptionAtTop={false}
selectComponent={Creatable}
promptTextCreator={(label) => {return "Search for " + label}}
/>
</div>
</FormGroup>
);
Help appreciated.

I figured it out, posting what it looks like as it might help others at some point
const renderSelect = ({input, items, filter}) => (
<FormGroup controlId="name" role="form" className="col-md-12">
<div className="group selectW" style={{width: '100%'}}>
<VirtualizedSelect
filterOptions={filter}
options={items}
onChange={input.onChange}
value={input.value}
name={input.name}
placeholder="Name"
onBlur={() => input.onBlur(input.value)}
autoBlur={true}
simpleValue={true}
multi={true}
clearable={false}
onBlurResetsInput={false}
onCloseResetsInput={false}
delimiter="|"
showNewOptionAtTop={false}
selectComponent={Creatable}
promptTextCreator={(label) => {return "Search for " + label}}
/>
</div>
</FormGroup>
);

Related

this.props.contextValue.store.getState is not a function when adding a custom input

I'm running into an issue with adding my own custon input after following the documentation for Autocomplete.
The error I get is "this.props.contextValue.store.getState is not a function" when adding my CustomSearchBox component. Can anyone advise what I'm doing wrong?
Usage:
<InstantSearch
searchClient={algoliaClient}
indexName="plp"
>
<CustomSearchBox /> // Errors when I add this
<Autocomplete
searchClient={algoliaClient}
placeholder="Search products"
detachedMediaQuery="none"
openOnFocus
/>
<RefinementList attribute="DIAMETER" />
<HitWrapper>
<Hits hitComponent={Hit} />
</HitWrapper>
</InstantSearch>
Custom search box component
import React from 'react';
import { connectSearchBox } from 'react-instantsearch-dom';
const SearchBox = ({ currentRefinement, isSearchStalled, refine }) => (
<form noValidate action="" role="search">
<input
type="search"
value={currentRefinement}
onChange={event => refine(event.currentTarget.value)}
/>
{isSearchStalled ? 'My search is stalled' : ''}
</form>
);
const CustomSearchBox = connectSearchBox(SearchBox);
export default CustomSearchBox;

checkboxes bootstrap react radio buttons not working

I'm building a form where it has two checkboxes the user is allowed to choose only one not both of them
I have used the react-bootstrap form
here is my code:
const [checked, setChecked] = useState("");
const [sechecked, setSechecked] = useState("");
return
<Form style={{ display: "flex" }}>
<Form.Check
value={checked}
onChange={(e) => setChecked(e.target.checked)}
type="radio"
aria-label="radio 1"
/>
Turkiye'den gonder
<Form.Check
value={sechecked}
onChange={(e) => {
setSechecked(e.target.sechecked);
console.log(checked);
}}
type="radio"
aria-label="radio 2"
/>
Turkiye'ye getir
</Form>
so, what I want is to only choose one checkbox and after that, the user can't choose the other one
Kindly add a name property to indicate the two options point to the same thing. In that case, only one can be selected
const [checked, setChecked] = useState("");
const [sechecked, setSechecked] = useState("");
return
<Form style={{ display: "flex" }}>
<Form.Check
value={checked}
name="useroption"
onChange={(e) => setChecked(e.target.checked)}
type="radio"
aria-label="radio 1"
/>
Turkiye'den gonder
<Form.Check
value={sechecked}
name="useroption"
onChange={(e) => {
setSechecked(e.target.sechecked);
console.log(checked);
}}
type="radio"
aria-label="radio 2"
/>
Turkiye'ye getir
</Form>

Can I autofocus on the first field in a redux-form created using a loop?

I have created a React component using redux-form and am looking to autoFocus on the first field. The fields are created by looping through an object and creating a field for each item in that object. When I use autoFocus in the JSX is autoFocuses on the last field in the form (which makes sense).
Does anyone know how I can autoFocus on the first field in the form?
Here is my component:
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
class BalanceForm extends Component {
constructor(props) {
super(props);
this.submitForm = this.submitForm.bind(this);
this.cancel = this.cancel.bind(this);
}
cancel() {
//not relevant
}
submitForm(e, values) {
//not relevant
}
render() {
return (
<div>
{this.props.balanceFormVisible &&
<div className="modal-background">
<div className="modal">
<form onSubmit={this.submitForm}>
{Object.keys(this.props.accounts).map((key) => {
return (
this.props.accounts[key].visible &&
<div key={this.props.accounts[key].name}>
<label className="form-label" htmlFor={this.props.accounts[key].name}>
{this.props.accounts[key].display}
</label>
<Field
name={this.props.accounts[key].name}
component="input"
type="number"
placeholder=""
autoFocus
/>
</div>
)
})}
<button type="submit">Submit</button>
<button onClick={ this.cancel } className="cancelbtn" >Cancel</button>
</form>
</div>
</div>
}
</div>
);
}
}
BalanceForm = reduxForm({form: 'balance'})(BalanceForm)
export default BalanceForm;
Thanks in advance :)
Solution to this was to conditionally render the form field. Thanks to Alexander Borodin for the inspiration...
{Object.keys(this.props.accounts).map((key, i) => {
console.log(key, i)
return (
this.props.accounts[key].visible &&
<div key={this.props.accounts[key].name}>
<label className="form-label" htmlFor={this.props.accounts[key].name}>
{this.props.accounts[key].display}
</label>
{(i === 0) ? (
<Field
name={this.props.accounts[key].name}
component="input"
type="number"
placeholder=""
autoFocus
/>
) : (
<Field
name={this.props.accounts[key].name}
component="input"
type="number"
placeholder=""
/>
)}
</div>
)
})}
Some of these either didn't compile or are a bit verbose. This worked for me:
{Object.keys(item)
.map((key, i) =>
<div className={`form-row ${key}`} key={key}>
<label>{key}</label>
<input value={item[key]}
type='text'
onChange={e => {
this._updateValue(key, e.target.value);
}}
autoFocus={i === 0}
/>
</div>
)}
Alternatively, if you hook in to ComponentDidMount, you can ask the DOM to focus the first existing field within the form.
Add a ref to the form
<form onSubmit={this.submitForm} ref='form'>
Use the ref to focus the element after mounting
componentDidMount() {
const firstInput = this.refs.form.querySelector('input')[0];
firstInput && firstInput.focus();
}
Try this:
{Object.keys(this.props.accounts).map((key, i) => {
return (
this.props.accounts[key].visible &&
<div key={this.props.accounts[key].name}>
<label className="form-label" htmlFor={this.props.accounts[key].name}>
{this.props.accounts[key].display}
</label>
<Field
name={this.props.accounts[key].name}
component="input"
type="number"
placeholder=""
{ (i === 0) ? 'autoFocus': ''}
/>
</div>
)
})}
I ran into an issue where autoFocus wasn't properly passing down from Field to the underlying component. Had to explicitly pass autoFocus in the props prop for Field.

react rerendering form causes focus/blur issue on state change

I have a form in a react component that has two change handlers, one for my two draftjs textareas, and one for my other text inputs:
onChangeEditor = (editorStateKey) => (editorState) => {
this.setState({ [editorStateKey]: editorState });
}
handleInputChange(event) {
event.preventDefault();
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
In my render method I have two views that I switch between depending on which view mode I am in, read or edit:
render () {
const Editable = () => (
<div className="editor">
<form className="editor-inner">
<h3>Redigerar: Anbudsbrev</h3>
<h4>Rubrik</h4>
<input type="text" key="text01" name="title" defaultValue={this.state.title} onBlur={this.handleInputChange} />
<h4>Text 1</h4>
<RichEditor editorState={this.state.editorState1} onChange={this.onChangeEditor('editorState1')} name="text01"/>
<h4>Citat</h4>
<input type="text" key="text02" name="quote01" defaultValue={this.state.quote01} onBlur={this.handleInputChange} />
<h4>Text 2</h4>
<RichEditor editorState={this.state.editorState2} onChange={this.onChangeEditor('editorState2')} name="text02" />
<EditorFooter {...this.props} submitForm={this.saveForm} />
</form>
</div>
);
const Readable = () => (
<div>
<h1 className="header66">{this.state.title}</h1>
<div className="text66">{this.state.text01}</div>
<div className="quote100">{this.state.quote01}</div>
<div className="text66">{this.state.text02}</div>
</div>
);
return (
<div>
{ this.props.isInEditMode ? <Editable /> : <Readable /> }
</div>
);
}
When I switch between inputs in my browser I have to click twice in order to get the focus on the right input.
I suspect that this is because a change is triggered on the "blur" event of each input, causing the form to rerender because state is changed. And when the form rerenders, it goes through the { this.props.isInEditMode ? <Editable /> : <Readable /> } which causes the input to lose focus.
The problem is that I don't know how to get around this.
I solved it myself.
It turns out that it was not a good idea to place the Editable and Readable inside of my component as I did. Instead I moved them out to their own components, and it works properly now.
class Editable extends React.Component {
render() {
return (
<div className="editor">
<form className="editor-inner">
<h3>Redigerar: Anbudsbrev</h3>
<h4>Rubrik</h4>
<input type="text" name="title" defaultValue={this.props.title} onChange={this.props.handleInputChange} />
<h4>Text 1</h4>
<RichEditor editorState={this.props.editorState1} onChange={this.props.onChangeEditor('editorState1')} name="text01" />
<h4>Citat</h4>
<input type="text" name="quote01" defaultValue={this.props.quote01} onChange={this.props.handleInputChange} />
<h4>Text 2</h4>
<RichEditor editorState={this.props.editorState2} onChange={this.props.onChangeEditor('editorState2')} name="text02" />
<EditorFooter {...this.props} submitForm={this.props.saveForm} />
</form>
</div>
);
}
};
class Readable extends React.Component {
render() {
return (
<div>
<h1 className="header66">{this.props.title}</h1>
<div className="text66">{this.props.text01}</div>
<div className="quote100">{this.props.quote01}</div>
<div className="text66">{this.props.text02}</div>
</div>
);
}
};

Redux-Form Field type number renderField step not working

I am encountering a strange problem when declaring a Field of type number and using the example renderField component on the redux-form website.
const renderField = ({ input, label, type, meta: { touched, error, warning } }) => (
<div>
<label>{label}</label>
<div>
<input {...input} placeholder={label} type={type}/>
{touched && ((error && <span>{error}</span>) || (warning && <span>{warning}</span>))}
</div>
);
Inside my render, I have a component of type number with a step size
<Field name="SmallStepSizeNumber" type='number' step={0.000001}
component={renderField} label="SmallStepSizeNumber"
validate={[ ]}
/>
All I'm trying to replicate is a normal html step size change, but it just steps by 1 ignoring my step size. The same happens when I try to set min/max/etc. Am I specifying this wrong? Is this a bug?
Passing a string instead of a number might works
const renderField = ({ input, label, type, meta: { touched, error, warning } }) => (
<div>
<input type="number" {...input} step="0.1" />
</div>
);
const Form = () => (
<Field
name="foobar"
component={renderField}
/>
);
Here's a jsfiddle https://jsfiddle.net/75rh036o/12/