1.0.2 • Published 1 year ago

react-native-advanced-form-validation v1.0.2

Weekly downloads
-
License
MIT
Repository
-
Last release
1 year ago

react-native-advanced-form-validation

Advanced form validation for React Native with support for complex rules, custom error messages, and real-time feedback with animations. This library integrates seamlessly with popular form libraries like Formik.

Installation

To install the package, use npm:

npm install react-native-advanced-form-validation

You will also need to install formik and yup if you haven't already:

npm install formik yup

Usage

Basic Setup

First, import the necessary modules and create your form validation schema using the provided helper function.

import React from 'react';
import { View, TextInput, Button, Text } from 'react-native';
import { Formik } from 'formik';
import { createFormikValidationSchema, withRealTimeValidation } from 'react-native-advanced-form-validation';

const RealTimeTextInput = withRealTimeValidation(TextInput);

const validationSchema = createFormikValidationSchema(['email', 'password', 'confirmPassword']);

const MyForm = () => {
  return (
    <Formik
      initialValues={{ email: '', password: '', confirmPassword: '' }}
      validationSchema={validationSchema}
      onSubmit={values => {
        console.log(values);
      }}
    >
      {({ handleChange, handleBlur, handleSubmit, values, errors, touched }) => (
        <View>
          <RealTimeTextInput name="email" placeholder="Email" />
          {touched.email && errors.email && <Text style={{ color: 'red' }}>{errors.email}</Text>}

          <RealTimeTextInput name="password" placeholder="Password" secureTextEntry />
          {touched.password && errors.password && <Text style={{ color: 'red' }}>{errors.password}</Text>}

          <RealTimeTextInput name="confirmPassword" placeholder="Confirm Password" secureTextEntry />
          {touched.confirmPassword && errors.confirmPassword && <Text style={{ color: 'red' }}>{errors.confirmPassword}</Text>}

          <Button onPress={handleSubmit} title="Submit" />
        </View>
      )}
    </Formik>
  );
};

export default MyForm;

Custom Validation Schema

You can customize the validation schema by adding your own validation rules:

import * as Yup from 'yup';
import { createFormikValidationSchema } from 'react-native-advanced-form-validation';

const customValidationSchema = Yup.object().shape({
  username: Yup.string().required('Username is required'),
  phoneNumber: Yup.string().matches(/^\d+$/, 'Phone number is not valid').required('Phone number is required'),
});

const validationSchema = createFormikValidationSchema(['email', 'password', 'confirmPassword']).concat(customValidationSchema);

const MyForm = () => {
  return (
    <Formik
      initialValues={{ email: '', password: '', confirmPassword: '', username: '', phoneNumber: '' }}
      validationSchema={validationSchema}
      onSubmit={values => {
        console.log(values);
      }}
    >
      {({ handleChange, handleBlur, handleSubmit, values, errors, touched }) => (
        <View>
          <RealTimeTextInput name="email" placeholder="Email" />
          {touched.email && errors.email && <Text style={{ color: 'red' }}>{errors.email}</Text>}

          <RealTimeTextInput name="password" placeholder="Password" secureTextEntry />
          {touched.password && errors.password && <Text style={{ color: 'red' }}>{errors.password}</Text>}

          <RealTimeTextInput name="confirmPassword" placeholder="Confirm Password" secureTextEntry />
          {touched.confirmPassword && errors.confirmPassword && <Text style={{ color: 'red' }}>{errors.confirmPassword}</Text>}

          <RealTimeTextInput name="username" placeholder="Username" />
          {touched.username && errors.username && <Text style={{ color: 'red' }}>{errors.username}</Text>}

          <RealTimeTextInput name="phoneNumber" placeholder="Phone Number" />
          {touched.phoneNumber && errors.phoneNumber && <Text style={{ color: 'red' }}>{errors.phoneNumber}</Text>}

          <Button onPress={handleSubmit} title="Submit" />
        </View>
      )}
    </Formik>
  );
};

export default MyForm;

Custom Error Messages

To customize error messages, you can create your own utility function:

// src/utils/customErrorMessages.js
export const getCustomErrorMessage = (error) => {
  switch (error.type) {
    case 'required':
      return `${error.path} cannot be empty`;
    case 'min':
      return `${error.path} must be longer than ${error.min} characters`;
    case 'email':
      return `Please enter a valid email address`;
    default:
      return `Invalid ${error.path}`;
  }
};

// Then use this function in your component:
import { getCustomErrorMessage } from './src/utils/customErrorMessages';

// In your component:
{touched.email && errors.email && <Text>{getCustomErrorMessage(errors.email)}</Text>}

Integration with Redux Form

For integration with Redux Form, you need to create custom field-level validation functions:

import { Field, reduxForm } from 'redux-form';
import validationSchemas from 'react-native-advanced-form-validation/src/validators';

const validate = values => {
  const errors = {};
  try {
    validationSchemas.email.validateSync(values.email);
  } catch (err) {
    errors.email = err.message;
  }
  try {
    validationSchemas.password.validateSync(values.password);
  } catch (err) {
    errors.password = err.message;
  }
  try {
    validationSchemas.confirmPassword.validateSync({
      password: values.password,
      confirmPassword: values.confirmPassword
    });
  } catch (err) {
    errors.confirmPassword = err.message;
  }
  return errors;
};

const MyReduxForm = ({ handleSubmit }) => (
  <View>
    <Field name="email" component={renderField} type="text" placeholder="Email" />
    <Field name="password" component={renderField} type="password" placeholder="Password" />
    <Field name="confirmPassword" component={renderField} type="password" placeholder="Confirm Password" />
    <Button onPress={handleSubmit} title="Submit" />
  </View>
);

const renderField = ({ input, placeholder, type, meta: { touched, error } }) => (
  <View>
    <TextInput {...input} placeholder={placeholder} type={type} />
    {touched && error && <Text>{error}</Text>}
  </View>
);

export default reduxForm({
  form: 'myReduxForm',
  validate,
})(MyReduxForm);

API

createFormikValidationSchema(fields: string[])

  • Description: Creates a validation schema for Formik based on the specified fields.
  • Parameters:
    • fields (string[]): An array of field names for which the validation schema should be created.
  • Returns: A Yup validation schema.

Default Validation Rules

  • email: Must be a valid email address.
  • password: Must be at least 8 characters long.
  • confirmPassword: Must match the password field.

withRealTimeValidation(Component: React.ComponentType)

  • Description: A higher-order component that provides real-time validation feedback with animations for the given input component.
  • Parameters:
    • Component (React.ComponentType): The input component to wrap with real-time validation feedback.
  • Returns: A new component with real-time validation feedback.

Example Components

RealTimeValidationHOC

This higher-order component provides real-time feedback for form validation:

import React, { useRef, useEffect } from 'react';
import { useFormikContext } from 'formik';
import { TextInput, View, Text, Animated, StyleSheet } from 'react-native';

const withRealTimeValidation = (Component) => ({ name, ...props }) => {
  const { values, errors, touched, handleChange, handleBlur } = useFormikContext();
  const errorAnim = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    if (touched[name] && errors[name]) {
      Animated.timing(errorAnim, {
        toValue: 1,
        duration: 300,
        useNativeDriver: true,
      }).start();
    } else {
      Animated.timing(errorAnim, {
        toValue: 0,
        duration: 300,
        useNativeDriver: true,
      }).start();
    }
  }, [touched, errors, name, errorAnim]);

  return (
    <View>
      <Component
        onChangeText={handleChange(name)}
        onBlur={handleBlur(name)}
        value={values[name]}
        {...props}
      />
      {touched[name] && errors[name] && (
        <Animated.View style={{ opacity: errorAnim }}>
          <Text style={styles.errorText}>{errors[name]}</Text>
        </Animated.View>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  errorText: {
    color: 'red',
    marginTop: 5,
  },
});

export default withRealTimeValidation;

License

This project is licensed under the MIT License.

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

Author

Mujahid Ramzan

1.0.2

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago