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
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;
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>
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.
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>
);
}
};
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/