How to press a next button and focus another text field input? - react-native

Version react hook form
^7.27.0
What I tried to follow and without successful
react hook form - Discussions 7818
react hook form - Issues 230
About what I have
I have 4 text field components at my screen, the name of each text field is name, documentation, email, password and I would like to know how can I setup some configuration that it will be pressed the NEXT button at keyboard and will focus the following text fields?
An example that I have inside at my component file, again I would like to press the next button and the next component that I will config, will be focus.
<TextField
name="name"
label={I18n.t('registerPersonal.fullNameLabel')}
placeholder={I18n.t('registerPersonal.fullNameInput')}
icon={<TypographyIcon fill={!!errors.name && theme.colors.attention} />}
error={errors.name?.message}
errors={errors}
control={control}
returnKeyType="next"
/>
<TextField
name="documentation"
label={I18n.t('registerPersonal.documentIdentificationLabel')}
placeholder={I18n.t('registerPersonal.documentIdentificationInput')}
icon={
<DocumentIcon
fill={!!errors.documentation && theme.colors.attention}
/>
}
error={errors.documentation?.message}
control={control}
returnKeyType="next"
/>
Some properties that I get at my personal hook
const {
control,
handleSubmit,
formState: { errors, isValid }
} = useForm({ resolver: yupResolver(schema) })
My component TextField
import { TextInputProps, Text } from 'react-native'
import { Control, useController } from 'react-hook-form'
import { Container, Wrapper, TextInput, Label } from './styles'
import theme from '../../global/styles/theme'
type TextFieldProps = {
placeholder?: string
label?: string
icon?: React.ReactNode
error?: string
errors?: {
[x: string]: any
}
name: string
control: Control
} & TextInputProps
export function TextField(props: TextFieldProps) {
const { placeholder, label, icon, error, errors, name, control, ...rest } =
props
const { field } = useController({
control,
defaultValue: '',
name
})
return (
<>
<Container>
{!!label && <Label>{label}</Label>}
<Wrapper hasLabel={!!label} hasError={!!error}>
{!!icon && icon}
<TextInput
value={field.value}
onChangeText={field.onChange}
placeholder={error ? error : placeholder}
placeholderTextColor={
error ? theme.colors.attention : theme.colors.grayColor
}
{...rest}
/>
</Wrapper>
{errors && errors.name && errors.name.type === 'matches' && (
<Text>{errors.name.message}</Text>
)}
</Container>
</>
)
}

your component must include ref prop like
<TextInput
ref={inputRef} // this one
value={field.value}
onChangeText={field.onChange}
placeholder={error ? error : placeholder}
placeholderTextColor={
error ? theme.colors.attention : theme.colors.grayColor
}
{...rest}
/>
then, you need to create ref from parent for each field
const emailRef = useRef(null);
const passwordRef = useRef(null);
after this, you need to add the props that is
onSubmitEditing={() => passwordRef.current.focus()} // to auto focus password field
finally,
<TextField
onSubmitEditing={() => passwordRef.current.focus()} // here
name="name"
label={I18n.t('registerPersonal.fullNameLabel')}
placeholder={I18n.t('registerPersonal.fullNameInput')}
icon={<TypographyIcon fill={!!errors.name && theme.colors.attention} />}
error={errors.name?.message}
errors={errors}
control={control}
returnKeyType="next"
/>

Related

Implementing react-hook-forms and react-select with radio buttons and multi inputs combo

Ready for a complicated one?
Using react-hook-forms and react-select using creatable (user creates multiple inputs on the fly)
I'm trying to implement a form that uses an option on 4 radio buttons, 2 of which reveal multi inputs (inputs that use react-select where the user can create multiple entries, not a dropdown) and trying to keep track of both the radio inputs and the multi inputs in the final useForm() object. I also need to be able to remove them if the user changes their mind or resets the form in total. Right now, the key values of registrationTypes changes when I change radioTwo and enter inputs. I also don't know how to remove user inputs. I'm using Controller to read the entries (although I've heard if you're using native HTML checkbox input, you have to use Register?) . Here's the code:
import styled from 'styled-components'
import Creatable from 'react-select/creatable'
import { Controller } from 'react-hook-form'
import { ErrorRow } from '../util/FormStyles'
import { FormRulesProps } from '../util/formRuleTypes'
import FormError from './FormError'
const registrationTypes = [
{
label: 'Allow anyone with the link to register',
value: 'radioOne',
},
{
label: 'Allow anyone with this email domain to register:',
value: 'radioTwo',
},
{ label: 'Allow anyone with this code to register:', value: 'radioThree' },
{
label: 'Define eligible users manually through eligibilty file.',
value: 'radioFour',
},
]
const RegistrationEligibilty = () => {
const {
control,
reset,
handleSubmit,
formState: { errors },
} = useForm<any>()
const [selectedRadio, setSelectedRadio] = useState({ regType: '' })
const onSubmit = (data: any) => {
console.log(data)
}
const handleSelected = (value: string) => {
setSelectedRadio({ ...selectedRadio, regType: value })
}
return (
<RegistrationEligibiltyContainer>
<form onSubmit={handleSubmit(onSubmit)}>
<FormRow>
<RadioWrapper>
{registrationTypes.map((rt) => (
<Controller
key={rt.value}
control={control}
name="radio"
render={({ field: { onChange, value } }: any) => (
<RadioGroup
// #ts-ignore
value={value}
onChange={(e: any) =>
onChange(e.target.value, handleSelected(rt.value))
}
>
<Radio
name={rt.value}
type="radio"
value={rt.value}
checked={selectedRadio.regType === rt.value}
/>
<TextRow
text={rt.label}
style={{ paddingLeft: '10px' }}
/>
{selectedRadio.regType === 'radioTwo' &&
rt.value === 'radioTwo' && (
<FormRow>
<div style={{ width: '90%' }}>
<Controller
name={rt.value}
control={control}
render={({ field }) => (
<Creatable
{...field}
isMulti
options={field.value}
value={field.value}
placeholder="Select domains"
/>
)}
/>
</div>
</FormRow>
)}
{selectedRadio.regType === 'radioThree' &&
rt.value === 'radioThree' && (
<FormRow>
<div style={{ width: '90%' }}>
<Controller
name={rt.value}
control={control}
render={({ field }) => (
<Creatable
{...field}
isMulti
options={field.value}
value={field.value}
placeholder="Select codes"
/>
)}
/>
</div>
</FormRow>
)}
</RadioGroup>
)}
/>
))}
</RadioWrapper>
</FormRow>
</FormContent>
</form>
</RegistrationEligibiltyContainer>
)
}
export default RegistrationEligibilty
The result looks like this:
https://imgur.com/a/6oGhqRb
I also need to be able to remove them if the user changes their mind or resets the form in total
If the component is unmounted, the value of the component is not included in the result. Make sure your Creatable is unmounted when the relevant radio is not selected

How to delete Call code from a phone number in React Native?

I'm using react-native-phone-number-input and i want to delete the call code from the number if the user types it.
my solution is :
class PhoneUserInput extends PureComponent {
...
<PhoneInput
ref={this.myRef}
onChangeFormattedText={(value) => {
if (value.substr(`+${this.myRef.current?.getCallingCode()}`.length)
.startsWith(`+${this.myRef.current?.getCallingCode()}`)) {
value = value.substr(`+${this.myRef.current?.getCallingCode()}`.length)
.replace(`+${this.myRef.current?.getCallingCode()}`, ''));
}
onChangeFormattedText(value);
console.log('formated value'+value);
}
}}
/>
}
I tried to the same thing on onChangeText props but it's doesn't give the effect instantly on the component.
Please try to do your work with
onChangeText={ (_text)=>{ //Your code} }
AND add :
value={value}
Here is a working example :
<PhoneInput
ref={phoneInput}
defaultValue={value}
value={value}
defaultCode="FR"
layout="first"
placeholder={label}
containerStyle={styles.phoneContainer}
onChangeText={(text) => {
setValue(text)
}}
onChangeFormattedText={(text) => {
setFormattedValue(text)
}}
withDarkTheme
withShadow
/>

How to check checkbox when there is an array in React Native?

I want to get checked friends using checkbox. But I not quite sure how i will achieve it, hope someone can help me.
This is my state:
state = {checked: false}
This is where I want to map array
{this.props.navigation.getParam('friends').map((name, key) => (
<View>
<Text>{name}</Text>
<CheckBox
checked={this.state.checked}
onPress={(val)=>{}}
/>
</View>))}
Note: Or Could someone write me an app/code snippet in snack.expo.io how to get only checked checkbox value
You can write a custom checkbox component
export default class CustomCheckbox extends Component {
constructor(props) {
super(props);
this.state = {
checked: false,
};
}
toggleChange(){
this.setState({checked: !this.state.checked});
}
render() {
return (
<View>
<Text>{this.props.name}</Text>
<CheckBox
checked={this.state.checked}
onPress={() => this.bind.toggleChange(this)}
/>
</View>
);
}
}
and import your CustomCheckbox component
import CustomCheckbox from "your CustomCheckbox.js path"
{this.props.navigation.getParam('friends').map((name, key) => (
<View>
<CustomCheckbox name={name} />
</View>
))}
Your code is pretty good to go, you just need to update a bit. You have following two options:
Your friend's array should have checked key within each containing object, then you can simply do something like this.
{
this.props.navigation.getParam('friends').map((item, key) => (
let {name, checked} = item // item is an object from friends array,the and it have name, checked and other keys
<View>
<Text>{name}</Text>
<CheckBox
checked={checked}
onPress={(val)=>{}}
/>
</View>))
}
Other is you to save the name of the person as key and true/false as the checked state, eg :
toggleCurrentFirendState = (item)=>{
this.setState((prevState)=>{
let {name} = item //get name from clicked friend from the list
return {
...prevState, //used spread operator, so that other states doesn't get mutat.
[name]:!prevState[name] //toogle state of clicked item
}
})
}
//within your render
{
this.props.navigation.getParam('friends').map((item, key) => (
let {name} = item // item is an object from friends array,the and it have name, checked and other keys
<View>
<Text>{name}</Text>
<CheckBox
checked={name ===this.state[name]} //see change
onPress={(val)=>{this.toggleCurrentFirendState(item)}}
/>
</View>))
}

How to set state on child component?

I have a component that renders out a list of buttons, lets call this 'ButtonList'. When one of the buttons is clicked, the event is bubbled up like so:
<ButtonList onButtonPressed={(mins) => { console.log(mins); }} />
In response to this, I want to hide that ButtonList and show another component that is currently hidden. The ButtonList has some state such as "state { visible: true }" that I want to toggle that stops it rendering. How do I make a call to toggle the state of that ButtonList and then also call my other component in this view to also toggle its visible state to show?
Thanks.
swappingComponentsExample = () => {
return (
<View>
{this.state.showButtonList ? (
<ButtonList
onButtonPressed={mins => {
this.setState({showButtonList: false});
console.log(mins);
}}
/>
) : (
<OtherComponent />
)}
</View>
);
};
// Renders both components but passes style override to hide the object
// ButtonList/OtherComponent are not destroyed and recreated using this method
hidingExample = () => {
return (
<View>
<ButtonList
onButtonPressed={mins => {
this.setState({showButtonList: false});
console.log(mins);
}}
style={!this.state.showButtonList && {display: 'none'}}
/>
<OtherComponent
style={this.state.showButtonList && {display: 'none'}}
/>
</View>
);
};

How to pass Picker value to parent component in React Native

I have a child Picker and it should pass selected value to it's parent. Components are in different .js files if it's important.
How can I pass the states of selected items?
parent
<RegionPicker regions={this.props.navigation.state.params.regionsJSON}/>
child:
export default class RegionPicker extends Component {
constructor(props) {
super(props);
this.state = {
selected1: '1',
selected2: '1'
};
}
onValueChange1(value: string) {
this.setState({selected1: value},
()=>{ console.log('new',this.state.selected1)}
);
}
onValueChange2(value: string) {
this.setState({selected2: value},
()=>{ console.log('new',this.state.selected2)}
);
}
render() {
return (
<View>
<Form>
<Item inlineLabel>
<Label style={{fontSize:16}}>Region</Label>
<Picker
iosHeader="Select one"
mode="dropdown"
placeholder='...'
selectedValue={this.state.selected1}
onValueChange={this.onValueChange1.bind(this)}
>
{this.getRegions(this.props.regions).map((item, index) => {
return (<Picker.Item label={item} value={item} key={index}/>)
})}
</Picker>
</Item>
<Item inlineLabel last>
<Label style={{fontSize:16}}>Suburb</Label>
<Picker
iosHeader="Select one"
mode="dropdown"
placeholder='...'
selectedValue={this.state.selected2}
onValueChange={this.onValueChange2.bind(this)}
>
{this.getSuburbs(this.state.selected1).map((item, index) => {
return (<Picker.Item label={item} value={item} key={index}/>)
})}
</Picker>
</Item>
</Form>
</View>
);
}
}
I would appreciate for any help and ideas.
In your parent, create a function that will capture your RegionPicker value. In this example, myFunction.
myFunction = (value) => {
console.log(value);
}
Then pass down your function as a prop, like so:
<RegionPicker
regions={this.props.navigation.state.params.regionsJSON}
onChange={e => { this.myFunction(e) }}
/>
Inside of RegionPicker you can simply call your function within onValueChange1() and onValueChange2().
this.props.onChange(value);
You should also .bind() your functions within the constructor. So inside of your RegionPicker you can add
this.onValueChange1 = this.onValueChange1.bind(this);
this.onValueChange2 = this.onValueChange2.bind(this);
And then just call
this.onValueChange1 in your Picker's onValueChange function.
As i thing you can do one thing you can get the value in the parent component
onValueChange={()=>{this.props.onValueChange1()}}
And in the component you call this function so you will get value
<RegionPicker onValueChange1={()=>{this.calculate()}}/>
calling the function in parent state will be
calculate (value: string){
**Do you logic stuff here **
}
May you get the value now