Giter VIP home page Giter VIP logo

react-native-formik's Introduction

React Native Formik Coverage Status License: MIT semantic-release NPM downloads NPM downloads

Forms are very verbose in React, and a lot of the time, you end up copy pasting a lot of boilerplate.

This repository is a set of high order components designed to help you take control again of your forms with React Native and Formik

Features

  • Easily composable set of helpers
  • Connects your React Native input to Formik with no boilerplate (See handleTextInput)
  • Add a type prop on your TextInput to take care of the input options based on the type (See withInputTypeProps)
  • Automatically focus the next input (See withNextInputAutoFocus)
  • Component agnostic: Handle any other form component with any design with withFormikControl

The point is to make your forms easy to write and provide features your users will expect with code as small as:

<MyInput label="Email" name="email" type="email" />
<MyInput label="Password" name="password" type="password" />
<Switch label="Accept terms and conditions" name="accepted" />
<DatePicker label="Birthday" name="birthday" />
<Button onPress={props.handleSubmit} title="SUBMIT" />

Table of contents

Installation

yarn add formik react-native-formik

Guides

Use any Input component

We can use any Input component. It will receive an error prop in addition to the usual TextInput props.

For instance, we can use react-native-material-textfield for the material design.

Create our form logic

We can compose our input with handleTextInput to make it boilerplate free. It will:

  • automatically manage its state in formik provided it has a name prop
  • automatically set its error prop if input is touched or form has been submitted
  • automatically adds the correct TextInput props dependending on its type (at the moment, email, password, digits, name are supported)

Let's add in withNextInputAutoFocusInput, which provides those awesome features:

  • when an input is submitted, it will automatically focuses on the next or submit the form if it's the last one
  • sets return key to "next" or "done" if input is the last one or not For withNextInputAutoFocus to work, the input component should be a class and implement a focus method.
import { compose } from "recompose";
import {
  handleTextInput,
  withNextInputAutoFocusInput
} from "react-native-formik";
import { TextField } from "react-native-material-textfield";

const MyInput = compose(
  handleTextInput,
  withNextInputAutoFocusInput
)(TextField);

To complement withNextInputAutoFocusInput, we need to create a Form component, for instance:

import { View } from "react-native";
import { withNextInputAutoFocusForm } from "react-native-formik";

const Form = withNextInputAutoFocusForm(View);

We can also create a validation schema, with yup. It's of course possible to use other validation possibilities provided by Formik, but yup makes validation and error messaging painless.

import * as Yup from "yup";

const validationSchema = Yup.object().shape({
  email: Yup.string()
    .required()
    .email("well that's not an email"),
  password: Yup.string()
    .required()
    .min(2, "pretty sure this will be hacked")
});

Then the form in itself becomes simple:

export default props => (
  <Formik
    onSubmit={values => console.log(values)}
    validationSchema={validationSchema}
    render={props => {
      return (
        <Form>
          <MyInput label="Email" name="email" type="email" />
          <MyInput label="Password" name="password" type="password" />
          <MyInput label="First Name" name="firstName" type="name" />
          <MyInput label="Last Name" name="lastName" type="name" />
          <Button onPress={props.handleSubmit} title="SUBMIT" />
        </Form>
      );
    }}
  />
);

Full code:

import React from "react";
import { Button, TextInput, View } from "react-native";
import { compose } from "recompose";
import { Formik } from "formik";
import * as Yup from "yup";
import {
  handleTextInput,
  withNextInputAutoFocusForm,
  withNextInputAutoFocusInput
} from "react-native-formik";
import { TextField } from "react-native-material-textfield";

const MyInput = compose(
  handleTextInput,
  withNextInputAutoFocusInput
)(TextField);
const Form = withNextInputAutoFocusForm(View);

const validationSchema = Yup.object().shape({
  email: Yup.string()
    .required("please! email?")
    .email("well that's not an email"),
  password: Yup.string()
    .required()
    .min(2, "pretty sure this will be hacked")
});

export default props => (
  <Formik
    onSubmit={values => console.log(values)}
    validationSchema={validationSchema}
    render={props => {
      return (
        <Form>
          <MyInput label="Email" name="email" type="email" />
          <MyInput label="Password" name="password" type="password" />
          <MyInput label="First Name" name="firstName" type="name" />
          <MyInput label="Last Name" name="lastName" type="name" />
          <Button onPress={props.handleSubmit} title="SUBMIT" />
        </Form>
      );
    }}
  />
);

Boilerplate-free, hassle-free, our form is awesome with minimum code required.

Custom components See it in Snack

withFormikControl usage

Thanks to withFormikControl, formik and react-native-formik can handle any custom component just like TextInputs, granted that the component takes as props:

{
  value: ValueType,
  setFieldValue: (value: ValueType) => void,
  error: ?string,
  setFieldTouched: () => void
}

If you want to use withNextInputAutoFocus, your component should be a class and have a focus method. Below is a simple example, a full example is available on ./src/Example/DatePicker.js.

Simple Example: using a Switch

A very simple example would be handling a Switch component in your form:

import React from "react";
import { Text, Switch as RNSwitch } from "react-native";
import { withFormikControl } from "react-native-formik";

class Switch extends React.PureComponent {
  render() {
    const { error, value, setFieldValue, label } = this.props;

    return (
      <React.Fragment>
        <RNSwitch
          value={value}
          ios_backgroundColor={error ? "red" : "transparent"}
          onValueChange={setFieldValue}
        />
        <Text>{label}</Text>
      </React.Fragment>
    );
  }
}

export default withFormikControl(Switch);

You can now use it in your form just like any other input:

<Switch label="Accept terms and conditions" name="termsAndConditionsAccepted" />

Formatting inputs

You may need to format inputs as the user types in. For instance, adding spaces in a telephone number (0612345678 -> 06 12 34 56 78). Here's how you would do it:

const formatPhoneNumber: string => string = (unformattedPhoneNumber) => ...;

...

<Formik
    render={({ values }) => {
      return (
        <Form>
          <MyInput name="phoneNumber" value={formatPhoneNumber(values.phoneNumber)} />
        </Form>
      );
    }}
/>

Move form above keyboard

The purpose of this section is to give you a solution to create a bottom form which will go up when the keyboard appears, and the content at the top at the page will disappear.

You have to:

import React, { PureComponent } from "react";
import { Image, Platform, ScrollView } from "react-native";
import Hide from "react-native-hide-with-keyboard";
import KeyboardSpacer from "react-native-keyboard-spacer";
import { Formik } from "formik";
import { Button, FormFormik, TextInputFormik } from "./components";
const cat = require("./cat.jpg");

class AdoptACat extends PureComponent<{}> {
  render() {
    return (
      <ScrollView
        style={styles.container}
        contentContainerStyle={styles.contentContainer}
        keyboardShouldPersistTaps="handled"
      >
        <Hide>
          <Image source={cat} style={styles.image} />
        </Hide>
        <View style={styles.fillContainer} />
        <Formik
          onSubmit={() => {}}
          render={props => (
            <FormFormik>
              <TextInputFormik
                name="catName"
                placeholder={"His name"}
                returnKeyType="next"
                type="name"
              />
              <TextInputFormik
                name="humanName"
                placeholder={"Your name"}
                returnKeyType="done"
                type="name"
              />
              <Button text={"Adopt him ..."} />
            </FormFormik>
          )}
        />
        {Platform.OS === "ios" && <KeyboardSpacer />}
      </ScrollView>
    );
  }
}

const styles = {
  container: {
    backgroundColor: "white",
    flex: 1,
    padding: 20
  },
  contentContainer: {
    flex: 1
  },
  fillContainer: {
    flex: 1
  },
  image: {
    alignSelf: "center",
    resizeMode: "contain"
  }
};

export default AdoptACat;

For Android, we don't have to use react-native-keyboard-spacer because android:windowSoftInputMode is in adjustResize mode. Indeed, the view is automatically resize and you don't have to fill it like on iOS.

Enjoy your life :

iOS

API

withFormikControl

See usage

handleTextInput

A set of default HOC to manage TextInputs. Includes withErrorIfNeeded, withInputTypeProps and withFormikControl remapped for specifically for the React Native TextInput

withErrorIfNeeded

Pass in the Formik error for the input as a prop, only if input has been touched or the form has been submitted

withError

Pass in the Formik error for the input as a prop.

withFocus

Add a focused prop to the input depending on its focus state.

withInputTypeProps

Let's face it, you'll always want to remove auto-capitalization for email inputs and use the email keyboard.

Using withInputTypeProps and passing a type, you'll always get the correct props for you input.

import { TextInput } from "react-native";
import { withInputTypeProps } from "react-native-formik";

const MyInput = withInputTypeProps(TextInput);

const emailInput = () => <MyInput type="email" />;

Authorized types as of now are email, password, digits and name. Setting another type has no consequence.

Check the props set by the type in the source!

withNextInputAutoFocus See example in Snack

  • when an input is submitted, it will automatically focuses on the next or submit the form if it's the last one
  • sets return key to "next" or "done" if input is the last one or not
  • ⚠️ your input component needs to be a class and needs to implement a focus function
  • ⚠️ Inputs need to be wrapped by withNextInputAutoFocusInput and the container of the inputs need to be wrapped in withNextInputAutoFocusForm.
import { TextInput, View } from "react-native";
import {
  withNextInputAutoFocusForm,
  withNextInputAutoFocusInput
} from "react-native-formik";

class CustomInput extends React.PureComponent {
  // Implement a focus function that focused whatever needs to be focused
  focus = () => { this.input.focus(); }

  render() {
    return (
      <TextField ref={input => this.input = input} {...this.props} />
    );
  }
}

const MyInput = withNextInputAutoFocusInput(CustomInput);
const Form = withNextInputAutoFocusForm(View);

export default props => (
  <Formik
    onSubmit={values => console.log(values)}
    validationSchema={validationSchema}
    render={props => {
      return (
        <Form>
          <MyInput label="Email" name="email" type="email" />
          <MyInput label="Password" name="password" type="password" />
          <MyInput label="First Name" name="firstName" type="name" />
        </Form>
      );
    }}
  />
);

withTouched

Pass in the Formik touched value for the input as a prop.

withPickerValues

Wraps your component into a TouchableOpacity which, when pressed, opens a dialog to pick a value. You need to provide a values props with the pickable items.

If you need to dismiss the picker's "Keyboard", you can use KeyboardModal.dismiss() like below.

import { TextInput, View } from "react-native";
import { compose } from "recompose";
import makeInput, {
  KeyboardModal,
  withPickerValues
} from "react-native-formik";

const MyPicker = compose(
  makeInput,
  withPickerValues
)(TextInput);

export default props => (
  <Formik
    onSubmit={values => {
      KeyboardModal.dismiss();
      console.log(values);
    }}
    validationSchema={validationSchema}
    render={props => {
      return (
        <View>
          <MyPicker
            name="gender"
            values={[
              { label: "male", value: "Mr" },
              { label: "female", value: "Mrs" }
            ]}
          />
        </View>
      );
    }}
  />
);

Guide

Move form above keyboard

The purpose of this section is to give you a solution to create a bottom form which will go up when the keyboard appears, and the content at the top at the page will disappear.

You have to:

import React, { PureComponent } from "react";
import { Image, Platform, ScrollView } from "react-native";
import Hide from "react-native-hide-with-keyboard";
import KeyboardSpacer from "react-native-keyboard-spacer";
import { Formik } from "formik";
import { Button, FormFormik, TextInputFormik } from "./components";
const cat = require("./cat.jpg");

class AdoptACat extends PureComponent<{}> {
  render() {
    return (
      <ScrollView
        style={styles.container}
        contentContainerStyle={styles.contentContainer}
        keyboardShouldPersistTaps="handled"
      >
        <Hide>
          <Image source={cat} style={styles.image} />
        </Hide>
        <View style={styles.fillContainer} />
        <Formik
          onSubmit={() => {}}
          render={props => (
            <FormFormik>
              <TextInputFormik
                name="catName"
                placeholder={"His name"}
                returnKeyType="next"
                type="name"
              />
              <TextInputFormik
                name="humanName"
                placeholder={"Your name"}
                returnKeyType="done"
                type="name"
              />
              <Button text={"Adopt him ..."} />
            </FormFormik>
          )}
        />
        {Platform.OS === "ios" && <KeyboardSpacer />}
      </ScrollView>
    );
  }
}

const styles = {
  container: {
    backgroundColor: "white",
    flex: 1,
    padding: 20
  },
  contentContainer: {
    flex: 1
  },
  fillContainer: {
    flex: 1
  },
  image: {
    alignSelf: "center",
    resizeMode: "contain"
  }
};

export default AdoptACat;

For Android, we don't have to use react-native-keyboard-spacer because android:windowSoftInputMode is in adjustResize mode. Indeed, the view is automatically resize and you don't have to fill it like on iOS.

Enjoy your life :

iOS

react-native-formik's People

Contributors

almouro avatar andrejcesen avatar betiol avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar elvinra avatar kishanio avatar maxhungry avatar micheleb avatar movibe avatar nil1511 avatar pierpo avatar pzupan avatar taboulot avatar tketa avatar tpucci avatar vincentlanglet avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-native-formik's Issues

Disable form submit on last input

I'd like to disable the automatic form submit which occurs on the last input withNextInputAutoFocus. It looks like withNextInputAutoFocus.js just establishes that the input is the last and then submits with no other alternative (lines 45-46). Am I missing something?

[withError] Don't override formik error when error props is defined.

Problem

I need to manage errors on a field :

  • One with Yup (validationSchema);
  • One with a call to an API;

withError automatically define the prop error from Yup for my children component.

However, if then in my form I define the props error like error={hasAPIError()} I don't have Yup's errors handle automatically. I need now to create a function that handle it for me like error={hasAPIError() || hasYupError()}.

In our case we totally forget to do it because we thought that Yup's errors will always be handle and transfer to my children component.

Solution

Current withError :

import { compose, mapProps } from "recompose";
import _ from "lodash";

import withFormik from "./withFormik";

const withError = compose(
  withFormik,
  mapProps(({ formik: { errors }, name, ...props }) => ({
    error: _.get(errors, name),
    ...props,
    name
  }))
);

export default withError;

Change I propose :

import { compose, mapProps } from "recompose";
import _ from "lodash";

import withFormik from "./withFormik";

const withError = compose(
  withFormik,
  mapProps(({ formik: { errors }, name, error, ...props }) => ({
    error: _.get(errors, name) || error, // Don't override errors that Formik handle for us
    ...props,
    name
  }))
);

export default withError;

What do you think about this update ?

withNextInputAutoFocus doesn't work with FlatList

Hi,

i use a FlatList inside a FieldArray inside a component wrapped with withNextInputAutoFocusForm

Current behavior

inputs inside the FlatList always have the done button

Expected behavior

inputs inside the FlatList should display the next button when this is not the last

Technical detail

FlatList has a renderItem prop but doesn't have the children prop

so, getInputs can find the inputs because it search children prop

const getInputs = children =>
React.Children.toArray(children).reduce((partialInputs, child) => {
if (child && child.props && child.props.children) {
return partialInputs.concat(getInputs(child.props.children));
}
if (child && child.props && !!child.props.name)
return partialInputs.concat(child);
return partialInputs;
}, []);

Demo

import { action } from '@storybook/addon-actions';
import { storiesOf } from '@storybook/react-native';
import { FieldArray, Formik } from 'formik';
import React from 'react';
import { FlatList, Text, TextInput, TouchableOpacity, View } from 'react-native';
import { handleTextInput, withNextInputAutoFocusForm, withNextInputAutoFocusInput } from 'react-native-formik';
import { compose } from 'redux';

const TextField = compose(
  handleTextInput,
  withNextInputAutoFocusInput,
)(TextInput);

const NextInputAutoFocus = withNextInputAutoFocusForm(View);

const initialFormValues = { someList: ['first item', 'second item', 'third item'] };

storiesOf('fields', module).add('fieldArray', () => (
  <Formik initialValues={initialFormValues} onSubmit={action('submit')}>
    {({ handleSubmit }) => (
      <NextInputAutoFocus>
        <FieldArray name="someList">
          {() => (
            <FlatList
              data={initialFormValues.someList}
              renderItem={({ index }) => <TextField name={`someList[${index}]`} />}
              keyExtractor={(_item, index) => index.toString()}
            />
          )}
        </FieldArray>
        <TouchableOpacity onPress={handleSubmit}>
          <Text>Submit</Text>
        </TouchableOpacity>
      </NextInputAutoFocus>
    )}
  </Formik>
));

It seems related to this issue #42 but i'm not sure this is the same problem


Thanks for this module : it's simple and usefull

Picker does not appear

I'm using your example code "MyPicker" no matter what I try, the Picker does not show. I'm using iOS. My code, which is essentially your example. What has changed?

import React from "react";
import { Button, TextInput, Text, View } from "react-native";
import {Formik} from 'formik'
import {compose} from 'recompose'
import makeInput, {handleTextInput,
        withNextInputAutoFocusForm,
        withNextInputAutoFocusInput,
        KeyboardModal,
        withPickerValues
} from 'react-native-formik'
import { TextField } from "react-native-material-textfield";
import * as Yup from 'yup'

const FormikInput = compose(
    handleTextInput,
    withNextInputAutoFocusInput
)(TextField)

const MyPicker = compose(
    makeInput,
    withPickerValues
)(TextInput)

const InputsContainer = withNextInputAutoFocusForm(View)

const validationSchema = Yup.object().shape({
    email: Yup.string()
        .required()
        .email("That's not a valid email"),
    password: Yup.string()
        .required()
        .min(3, "That's too small"),
    gender: Yup.string()
})

export default ThisForm => (
    <Formik
        onSubmit={values => {KeyboardModal.dismiss(); console.log(values)}}
        validationSchema={validationSchema}
    >
        {props => {
            return (
                <InputsContainer style={{ padding: 10 }}>
                    <FormikInput label="email" name="email" type="email" />
                    <FormikInput label="password" name="password" type="password" />
                    <MyPicker
                        name="gender"
                        values={[{label: 'male', value: 'M'}, {label: 'female', value: 'F'}]}
                    />
                    <Button onPress={props.handleSubmit} title="Submit" />
                    
                    {/* <Text style={{fontSize: 20}}>{JSON.stringify(props, null, 2)}</Text> */}
                </InputsContainer>
            )
        }}
    </Formik>
)

Incompatibility with formik v1

It seems react-native-formik is not compatitble with the new version of formik.

My error:

TypeError: TypeError: Cannot read property 'setFieldValue' of undefined

This error is located at:
    in mapProps(getContext(WithFocusProp)) (created by getContext(mapProps(getContext(WithFocusProp))))
    in getContext(mapProps(getContext(WithFocusProp))) (created by mapProps(getContext(mapProps(getContext(WithFocusProp)))))
    in mapProps(getContext(mapProps(getContext(WithFocusProp)))) (created by Styled(mapProps(getContext(mapProps(getContext(WithFocusProp))))))
    in Styled(mapProps(getContext(mapProps(getContext(WithFocusProp)))))

dependency issues

Something broke for me going from v1.7.1 to v1.7.4:

Unable to resolve "@bam.tech/react-native-modalbox" from "node_modules/react-native-formik/src/withPickerValues/KeyboardModal.js"

Setting to strictly "react-native-formik": "1.7.1", in package.json fixed it for me.

Support Formik 1.0.1+

  • We need to replace withFormik by connect
  • do we want to handle retrocompatibility? or submit a 2.0 with a breaking change?

WithNextInputAutoFocusInput Formik children is not updating

the issue is that the children is not updating when i dynamically add new input fields to formik,

example

<Formik>
  <FormWrap>
    <Input/>
    {condition <Input/>}
  </Formik>
  <Button>
</FormWrap>

now when i finish typing in the second field the auto focus will jump to the first field which shouldn't happen,
what happen is that the children will allows be the first input, even after changing the condition to true

Using React Hooks & withNextInputAutoFocus together

Thanks for this awesome lib, it has been fun all the time to use it. I have a question though on how could i use withNextInputAutoFocus and my functional Hooks component. According to your docs, using withNextInputAutoFocus requires us to have a focus method, with a sole purpose to focus on the element.

The problem occurs when I'am using hooks. As we know that in functional component you can't have a method, on the other hand, because you want to use hooks you cannot use class. So I'am stuck in the middle of both. I really hope I can use Hooks and withNextInputAutoFocus together as I really enjoyed working with both.

react-native-formik throws an error and doesn't work AT ALL with Formik v2

This error comes when typing into any text field -
TypeError: undefined is not an object (evaluating '(i === 0 ? obj : resVal)[pathArray[i]]')

This error occurs even with the example code in README.

It seems like work on react-native-formik stopped around the time the last stable version of Formik 1.x.x came out, which was 1.5.8, the package has not been updated for Formik v2

Right now it's working with [email protected], for anyone who wishes to use this package.

Initial value not set

When using the makeReactNativeField, the initialValue is no longer set (since v1.0.2).
I guess setFormikInitialValue hoc is not setting the initial value even if it is set in its props.

const setFormikInitialValue = WrappedInput => {
  return class WithFocusProp extends React.PureComponent {
    constructor(props) {
      super(props);
      props.formik.setFieldValue(props.name, "");
    }

...

Confused by formatting inputs example on home page

In this example Formatting Inputs I'm confused by this line:

const formatPhoneNumber: string => string = (unformattedPhoneNumber) => ...;

Why the double function indirection? How exactly is that adding spaces? I'm guessing it's just a sample to say that if "value" prop is a function, it'll get called but store the value untransformed.

Would love some hints.

withNextInputAutoFocus does not work with arrays of (dynamic) components.

When attempting to build a form dynamically using an array of Components, withNextInputAutoFocus does not set the keyboard "enter" button to advance to the next field.

For example:

const config = [
  { label: "Email", name: "email", type: "email" },
  { label: "Password", name: "password", type: "password" },
  { label:"First Name", name: "firstName", type: "name" },
  { label: "Last Name", name: "lastName", type: "name" },
]

export default props => (
  <Formik
    onSubmit={values => console.log(values)}
    validationSchema={validationSchema}
    render={props => {
      return (
        <Form>
          {
            config.map( item =>
              <MyInput label={item.label} name={item.name} type={item.type} />
            )
          }  
          <Button onPress={props.handleSubmit} title="SUBMIT" />
        </Form>
      );
    }}
  />
);

The above code will render, but the autofocus feature does not work.

TypeError: undefined is not an object (evaluating '(i === 0 ? obj : resVal)[pathArray[i]]')

I'm basically using the demo Gist verbatim:

https://snack.expo.io/@almouro/react-native-formik-gist

When I type a single letter into any text field I get the error:

TypeError: undefined is not an object (evaluating '(i === 0 ? obj : resVal)[pathArray[i]]')

I tried removing validationSchema and I still got the error. Separately, I tried removing withNextInputAutoFocusForm and withNextInputAutoFocusInput, and still got the problem. It feels like a bug in handleTextInput. Maybe I'm doing something stupid in the syntax below.

From package.json:

"formik": "^2.1.4",
"react-native-formik": "^1.7.8",
"react-native-material-textfield": "^0.16.1",
"recompose": "^0.30.0",
"yup": "^0.28.3"

Code:

import React from 'react';
import { Button, ScrollView, View } from 'react-native';
import { compose } from 'recompose';
import { Formik } from 'formik';
import * as Yup from 'yup';
import {
  handleTextInput,
  withNextInputAutoFocusForm,
  withNextInputAutoFocusInput
} from 'react-native-formik';
import { OutlinedTextField } from 'react-native-material-textfield';

const MyInput = compose(
  handleTextInput,
  withNextInputAutoFocusInput
)(OutlinedTextField);
const Form = withNextInputAutoFocusForm(View);

const validationSchema = Yup.object().shape({
  country: Yup.string()
    .required('Required.')
    .length(2, 'Must be 2 letter country code.'),
});

const RegistrationForm = props => (
  <Formik
    onSubmit={values => console.log(values)}
    validationSchema={validationSchema}
  >
    {props => (
      <Form>
        <MyInput label="Country" name="country" type="name"/>
        <MyInput label="Business name" name="name" type="name"/>
        <MyInput label="Business website" name="website" type="email"/>
        <MyInput label="Business phone number" name="phone" type="digits"/>
        <MyInput label="Address line 1" name="addressLine1" type="name"/>
        <MyInput label="Address line 2" name="addressLine2" type="name"/>
        <MyInput label="City" name="city" type="name"/>
        <MyInput label="State" name="state" type="name"/>
        <MyInput label="Zip code" name="zip" type="digits"/>
        <Button onPress={props.handleSubmit} title="SUBMIT" />
      </Form>
    )}
  </Formik>
);

export default class MyScreen extends React.Component {
  render() {
    return (
      <ScrollView style={{ padding: 30 }}>
        <RegistrationForm/>
      </ScrollView>
    );
  }
}

Handle nested fields

The library does not work for nested fields (for example user.username) since the value is accessed directly from the object.

In makeReactNativeField.js:

mapProps(({ formik: { setFieldValue, setFieldTouched, values }, name, ...props }) => ({
    value: values[name],
    // ...
}))

Same in withError.js.

Suggested solution

I think we could just add a selector function?

const getValue = (values, name) => {
  if (!name.includes('.')) {
    return values[name];
  } else {
    const nestedKeys = name.split('.');
    selectedValue = values[nestedKeys[0]];
    for (let i = 1; i < nestedKeys.length; i += 1) {
      selectedValue = selectedValue[nestedKeys[i]];
    }

    return selectedValue;
  }
}

And

mapProps(({ formik: { setFieldValue, setFieldTouched, values }, name, ...props }) => ({
    value: getValue(values, name),
    // ...
}))

I'll open a PR this week

withNextInputAutoFocus doen't work with custom components at all

I wasted all day trying to get it to work with a custom input component and all the difference I could make is to either make the form submit by tapping Next button, or to defocus the field. Unlike the other issue here I don't even have any nesting. Unlike TextField and inbuilt native inputs it won't work in any way if I use a custom element that is seemingly compliant with the requirements set in readme. Here's the element wrapper:

export default class StyledInput extends React.Component {

  constructor(props) {
    super(props);
  }

  focus = () => this.setState({ focused: true });

  render() {
    return (
      <TextField {...this.props} />
    );
  }
}

Here's how it used:

const Form = withNextInputAutoFocusForm(View);
const MyInput = withNextInputAutoFocusInput(StyledInput);

export default class Login extends Screen {
...
  render() {
    return (
      <View >
          <Formik
            onSubmit={(values, actions) => this.formSubmit(values, actions)}
            validationSchema={validationSchema}
            initialValues={{
              ...
            }}
            render={formikProps => {
              return (
                <Form>

                  <MyInput
                    label='Blah'
                    autoFocus
                    name='login'
                    type='email'
                  />

                  <MyInput
                    label='Password'
                    name='password'
                    type='password'
                  />

                </Form>
              );
            }}
          />
        </View>
    );
  }
}

Am I doing something wrong or is it really broken?

How to add initialValues?

Hi, I'm really excited about this package. But the initialValues won't work with this lib. So, How to add initialValues?

Ability to perform field-level validations?

The <Field /> component from Formik allows for field-level validation and currently this is a bit of a pain to do with react-native-formik. Are there any plans to support it out of the box?

Picker doesnt pass the value to props

I can get all the values like email and password in console.log except selected value for picker

import React from 'react';
import { Text, View ,StyleSheet, Button, TextInput } from 'react-native';
import { TextField } from 'react-native-material-textfield';
import { compose } from 'recompose';
import { Formik } from 'formik';
import Yup from 'yup';
import makeInputGreatAgain, {
    withNextInputAutoFocusForm,
    withNextInputAutoFocusInput,
    withPickerValues
} from 'react-native-formik';

export class MaterialTextInput extends React.PureComponent {
    // Your custom input needs a focus function for `withNextInputAutoFocus` to work
    focus() {
        this.input.focus();
    }

    render() {
        const { error, touched, ...props } = this.props;
        //
         const displayError = !!error && touched;
         const errorColor = 'rgb(239, 51, 64)';

        return (
            <View>
                <TextField
                    ref={input => (this.input = input)}
                    labelHeight={12}
                    baseColor={displayError ? errorColor : '#1976D2'}
                    tintColor="#2196F3"
                    textColor="#212121"
                    {...props}
                />
                <Text
                    style={{
                        textAlign: 'right',
                        color: displayError ? errorColor : 'transparent',
                        height: 20,
                    }}
                >
                    {error}
                </Text>
            </View>
        );
    }
}

const MyInput = compose(makeInputGreatAgain, withNextInputAutoFocusInput)(MaterialTextInput);
const Form = withNextInputAutoFocusForm(View);
const MyPicker = withPickerValues(TextInput);

const validationSchema = Yup.object().shape({
    email: Yup.string()
        .required('please! email?')
        .email("well that's not an email"),
    password: Yup.string()
        .required()
        .min(2, 'pretty sure this will be hacked'),
});

export default props => (
    <Formik
        onSubmit={values => console.log(values)}
        validationSchema={validationSchema}
        render={props => {
            return (
                <Form>
                    <MyInput label="Email" name="email" type="email" />
                    <MyInput label="Password" name="password" type="password" />
                    <MyInput label="First Name" name="firstName" type="name" />
                    <MyInput label="Last Name" name="lastName" type="name" />
                    <MyPicker
                        name="gender"
                        values={[{ label: 'male', value: 'Mr' }, { label: 'female', value: 'Mrs' }]}
                    />
                    <Button onPress={props.handleSubmit} title="SUBMIT" />
                   
                </Form>
            );
        }}
    />
);

Submission on blur for each individual input should be an optional configuration

At this point the majority of mobile app settings screens do not use a submit button, they submit the fields on blur. At present, this isn't possible because Formik uses blur for other purposes and blocks the usage of blur for submission. Since react-native-formik is meant to make Formik more friendly toward react-native, one of the configuration options should be individual inputs which submit on blur.

BackAndroid error when using React Native 0.58

After upgrading to React Native 0.58, I experienced this error on Android:

BackAndroid is deprecated and has been removed from this package. Use BackHandler instead.

I tracked the issue down to @bam.tech/react-native-modalbox:

'use strict';

var React = require('react');
var PropTypes = require('prop-types');
var {
  View,
  StyleSheet,
  PanResponder,
  Animated,
  TouchableWithoutFeedback,
  Dimensions,
  Easing,
  BackAndroid,
  BackHandler,
  Platform,
  Modal,
  Keyboard
} = require('react-native');

var createReactClass = require('create-react-class');

var BackButton = BackHandler || BackAndroid;
...

Removing BackAndroid from this file seems to solve the problem.

Version 1.7.0 of react-native-modalbox makes this fix.

You may want to publish a new version of @bam.tech/react-native-modalbox that removes the deprecated BackAndroid.

withNextInputAutoFocusInput goes to next input on new line for a multiline input

using the provided example of:

const MyInput = compose(
    handleTextInput,
    withNextInputAutoFocusInput
)(TextField);

on a <MyInput name="multitest" multiline={true} /> it will go to the next input upon pressing enter instead of adding a new line to the multiline field.

I thought I could work around it by doing this:

const MyMultiInput = compose(
    handleTextInput
)(TextField);

but unfortunately then the normal input above the "multitest" is done it skips the focus to the input below "multitest" that is another normal input.

Any thoughts on how to get around this besides making the multi fields the first or last fields in the form?

KeyboardSpacer collapses momentarily when transitioning between fields

I'm not sure if it's expect behavior or not, but I tried out the advanced example and (at least on IOS) the keyboard closes and the fields reposition to the expanded state for a moment before the next field takes focus. The result is that the form jumps around when using the next button on the keyboard. This does not happen when tapping on the next field or any other field.

Custom input with initial value is not working

If we give initial value as per the code in WithFormikControl the initila value from props always overrides the value got from getValue

const withFormikControl = compose( withErrorIfNeeded, connect, mapProps( ({ formik: { values, setFieldValue, setFieldTouched }, name, value, ...props }) => ({ value: get(values, name) === undefined ? value : get(values, name), setFieldValue: (value, ...args) => setFieldValue(name, value, ...args), setFieldTouched: (value, ...args) => setFieldTouched(name, value, ...args), name, ...props }) ) );

this should be the code

withPickerValues stopped working on IOS

The picker no longer opens for me on IOS. It still works as expected on Android. I can see the KeyboardModal is called if it is IOS at line 47 of PickerModal.js when the Platform is IOS.

It appears that this issue is related to a wrapper I've placed around the App. In order to disable the Expo logger in terminal, I'm calling Logs.disableExpoCliLogging and then

const AppEntry = () => {
  const App = require('./App').default;
  return <App />;
};
registerRootComponent(AppEntry);

If I use the default entry node_modules/expo/AppEntry.js the picker modal works on IOS.

using checkbox

Hi ,
is there any way i can apply formik in react native for checkbox ?

i want to the checkbox to be required, any chance this is doable ?

thanks in advance

Nested Form Walkthrough

I see that the normal formik library supports nested forms...I simply need a way to send an object through the form with shape.

{ applicant_form: { user_id,
          info_attributes: {
                                     first_name, 
                                     last_name
                }
        }
}

Add a Debugging component

We could add something as simple as a <Text /> that shows JSON.stringinfy(formikContext, null, 2).
Very useful when trying to debug issues :)

The automated release is failing 🚨

🚨 The automated release from the master branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this πŸ’ͺ.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here is some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


The push permission to the Git repository is required.

semantic-release cannot push the version tag to the branch master on remote Git repository.

Please refer to the authentication configuration documentation to configure the Git credentials on your CI environment.


Good luck with your project ✨

Your semantic-release bot πŸ“¦πŸš€

Focus next input with custom button

I have UI that has iOS keyboard navigation options to focus next/previous input. I am unable to focus the inputs using the button.
image

Can anyone help me with any method available to focus the input?

withNextInputAutoFocus does not work with nested components

Description

When using self-closing-tag components to generate text fields in a form, the withNextInputAutoFocusForm does not register the generated textInputs and the expected behaviour does not work : pressing "OK" with a textInput focused submits the entire form.

Steps to reproduce / example

const Form = withNextInputAutoFocusForm(View);

export class ReportForm extends PureComponent<PropsType, StateType> {
  renderForm = ({ values, handleSubmit }: { values: any, handleSubmit: Function }) => {
    return (
        <Form>
            <AircraftInformationSection />
      </Form>
    );
  };

  render() {
    return (
      <Formik
        // ...
        render={this.renderForm}
      />
    );
  }
}
export class AircraftInformationSection extends PureComponent<PropsType> {
  render() {
    return (
      <View>
        <TextInput
          name="aircraftInformationSectionType"
          // ...
        />
      </View>
    );
  }
}

In this case, getInputs does not see any children in the props of <AircraftInformationSection />

Ideas of technical solution

Create a Provider/Consumer system with textFields subscribing to the form.
Add a prop to the form to specify the order of the fields to be focused.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.