Giter VIP home page Giter VIP logo

react-reactive-form's Introduction

React Native Game Engine

React Reactive Forms

Build Status Backers on Open Collective Sponsors on Open Collective NPM Version code style: prettier gzip size PRs welcome

It's a library inspired by the Angular's Reactive Forms, which allows to create a tree of form control objects in the component class and bind them with native form control elements.

Features

  • UI independent.
  • Zero dependencies.
  • Nested forms.
  • Subscribers for value & status changes of controls.
  • Provides a set of validators & also supports custom sync & async validators.
  • FormGenerator api to create large forms with less code.
  • Better form management with FormGroup & FormArray apis.
  • Customizable update strategy for better performace with large forms.

Installation

npm install react-reactive-form --save

Basic Example

import React, { Component } from 'react';
import {
    FormBuilder,
    FieldGroup,
    FieldControl,
    Validators,
 } from "react-reactive-form";

const TextInput = ({ handler, touched, hasError, meta }) => (
  <div>
    <input placeholder={`Enter ${meta.label}`} {...handler()}/>
    <span>
        {touched
        && hasError("required")
        && `${meta.label} is required`}
    </span>
  </div>  
)
export default class Login extends Component {
    loginForm = FormBuilder.group({
        username: ["", Validators.required],
        password: ["", Validators.required],
        rememberMe: false
    });
    handleReset=() => {
        this.loginForm.reset();
    }
    handleSubmit=(e) => {
        e.preventDefault();
        console.log("Form values", this.loginForm.value);
    }
    render() {
        return (
              <FieldGroup
                control={this.loginForm}
                render={({ get, invalid }) => (
                  <form onSubmit={this.handleSubmit}>

                    <FieldControl
                      name="username"
                      render={TextInput}
                      meta={{ label: "Username" }}
                    />

                    <FieldControl
                      name="password"
                      render={TextInput}
                      meta={{ label: "Password" }}
                    />

                    <FieldControl
                      name="rememberMe"
                      render={({handler}) => (
                        <div>
                          <input {...handler("checkbox")}/>
                        </div>
                      )}
                    />
                    <button
                      type="button"
                      onClick={this.handleReset}
                    >
                      Reset
                    </button>
                    <button
                      type="submit"
                      disabled={invalid}
                    >
                      Submit
                    </button>
                  </form>
                )}
              />
        );
    }
}
import React, { Component } from 'react';
import {
    Validators,
    FormGenerator
 } from "react-reactive-form";
// Input component
const TextInput = ({ handler, touched, hasError, meta }) => (
  <div>
    <input placeholder={`Enter ${meta.label}`} {...handler()}/>
    <span>
        {touched
        && hasError("required")
        && `${meta.label} is required`}
    </span>
  </div>  
)
// Checkbox component
const CheckBox = ({ handler }) => (
    <div>
      <input {...handler("checkbox")}/>
    </div>
  )
// Field config to configure form
const fieldConfig = {
    controls: {
        username: {
            options: {
                validators: Validators.required
            },
            render: TextInput,
            meta: { label: "Username" }
        },
        password: {
            options: {
                validators: Validators.required
            },
            render: TextInput,
            meta: { label: "Password" }
        },
        rememberMe: {
            render: CheckBox
        },
        $field_0: {
            isStatic: false,
            render: ({ invalid, meta: { handleReset } }) => (
                <div>
                    <button
                      type="button"
                      onClick={handleReset}
                    >
                      Reset
                    </button>
                    <button
                      type="submit"
                      disabled={invalid}
                    >
                      Submit
                    </button>
                </div>
            )
        }
    },
}
export default class Login extends Component {
    handleReset=() => {
        this.loginForm.reset();
    }
    handleSubmit=(e) => {
        e.preventDefault();
        console.log("Form values", this.loginForm.value);
    }
    setForm = (form) => {
        this.loginForm = form;
        this.loginForm.meta = {
            handleReset: this.handleReset
        }
    }
    render() {
        return (
            <form onSubmit={this.handleSubmit}>
                <FormGenerator
                    onMount={this.setForm}
                    fieldConfig={fieldConfig}
                />
            </form>
        );
    }
}

Add Controls Dynamically

You can also create controls without even initializing the group control object with the help of new react form components ( FieldGroup, FieldControl, FieldArray).

import React, { Component } from 'react'
import { FieldGroup, FieldControl, Validators } from 'react-reactive-form'

export default class Login extends Component {
  handleSubmit = (e, value) => {
    console.log('Form values', value)
    e.preventDefault()
  }
  render() {
    return (
      <FieldGroup
        render={({ get, invalid, reset, value }) => (
          <form onSubmit={e => this.handleSubmit(e, value)}>
            <FieldControl
              name="username"
              options={{ validators: Validators.required }}
              render={({ handler, touched, hasError }) => (
                <div>
                  <input {...handler()} />
                  <span>
                    {touched && hasError('required') && 'Username is required'}
                  </span>
                </div>
              )}
            />
            <FieldControl
              name="password"
              options={{ validators: Validators.required }}
              render={({ handler, touched, hasError }) => (
                <div>
                  <input {...handler()} />
                  <span>
                    {touched && hasError('required') && 'Password is required'}
                  </span>
                </div>
              )}
            />
            <FieldControl
              name="rememberMe"
              render={({ handler }) => (
                <div>
                  <input {...handler('checkbox')} />
                </div>
              )}
            />
            <button type="button" onClick={() => reset()}>
              Reset
            </button>
            <button type="submit" disabled={invalid}>
              Submit
            </button>
          </form>
        )}
      />
    )
  }
}

So, it's not mandatory that you need to define your control separately but if you want a better control over your form state then you should do that, if your controls are dynamic then you can also initalize the empty group control and add the controls later. See the example:

import React, { Component } from 'react'
import {
  FormBuilder,
  FieldGroup,
  FieldControl,
  Validators
} from 'react-reactive-form'

export default class Login extends Component {
  // Initialize the empty group control
  loginForm = FormBuilder.group({})

  handleReset = e => {
    this.loginForm.reset()
  }
  handleSubmit = e => {
    console.log('Form values', this.loginForm.value)
    e.preventDefault()
  }
  render() {
    return (
      <FieldGroup
        control={this.loginForm}
        render={({ get, invalid, reset, value }) => (
          <form onSubmit={this.handleSubmit}>
            <FieldControl
              name="username"
              options={{ validators: Validators.required }}
              render={({ handler, touched, hasError }) => (
                <div>
                  <input {...handler()} />
                  <span>
                    {touched && hasError('required') && 'Username is required'}
                  </span>
                </div>
              )}
            />
            <FieldControl
              name="password"
              options={{ validators: Validators.required }}
              render={({ handler, touched, hasError }) => (
                <div>
                  <input {...handler()} />
                  <span>
                    {touched && hasError('required') && 'Password is required'}
                  </span>
                </div>
              )}
            />
            <FieldControl
              name="rememberMe"
              render={({ handler }) => (
                <div>
                  <input {...handler('checkbox')} />
                </div>
              )}
            />
            <button type="button" onClick={this.handleReset}>
              Reset
            </button>
            <button type="submit" disabled={invalid}>
              Submit
            </button>
          </form>
        )}
      />
    )
  }
}

Documentation

Code Sandboxes

Try out react-reactive-forms in these sandbox versions of the Examples.

FAQ

How is it different from other form libraries?

React has many libraries which works on the form logic, but here are some concerns with these:

Code Complexity

If youโ€™re using the redux-form then you should know the pain, for just a two field login form youโ€™d to write the store logic.In RRF you can see that how simple is to deal with simple and complex forms.

And one of the awesome thing is that you can just write your form controls logic anywhere in your application.

Dependencies

Many libraries come with dependencies for e.g redux is required for redux-form, So what If Iโ€™m using another state management or not event using any. According to Dan Abramov,ย form state is inherently ephemeral and local, so tracking it in Redux (or any kind of Flux library) is unnecessary. RRF comes with zero dependency, So itโ€™s totally up to you that how you want to save your form state if needed.

Performance

Now thatโ€™s a big problem with almost all libraries when you're dealing with large forms.

How RRF does solve performance issues ?

  • It uses subscription to update the components so rather updating all the fields on every input changes, it only update the particular field for which the state change takes place.
  • RRF has a nice option to define that when(blur, submit or change) to update your form's state by using the updateOn property.

Dynamic Changes

With the help of subscribers it's pretty easy to listen for a particular state changes and modify the controls accordingly.

What are value and status changes subscribers?

RRF uses inbuilt Subject, A Subject is an object with the methodย next(v).To feed a new value to the Subject,RRF just calls theย next(theValue), and it will be multicasted to the Observers registered to listen to the Subject. So basically it provides three subjects for each AbstractControl valueChanges, statusChanges and stateChanges and additional two subjects for FormControl ( onValueChanges, onBlurChanges) You can register an observer to a particular Subject to do some actions whenever some particular changes happen.

Example:

componentDidMount() {
  this.myForm.get(โ€œgenderโ€).valueChanges.subscribe((value) => {
    // do something
  })
}

Checkout the Basic usage guide for more details.

How the Field components work?

Field components are subscribed to the state changes of a particular control which means that itโ€™ll re-render the component only when itโ€™s state changes disregarding of other field changes.You can also implement your custom wrappers by using the stateChanges Subject.

How updateOn feature works?

Its an another performance booster in RRF, it just holds the computation needed to be made after every keystroke or value changes until you want to execute.It has three options change(default), blur and submit, you can define all of them at both field and record level.

Is this library compatible with React Native?

Yes, this library works with react-native also, currently it supports react-native TextInput and Switch component.

Note:

If you're using react-native then please add the following line of code in index.js of your project to avoid error in android devices.

import "core-js/es6/symbol";
import "core-js/fn/symbol/iterator";

Let's make React Reactive Forms better! If you're interested in helping, all contributions are welcome and appreciated.

And don't forget to star the repo, I will ensure more frequent updates! Thanks!

Contributors

This project exists thanks to all the people who contribute.

Backers

Thank you to all our backers! ๐Ÿ™ [Become a backer]

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]

react-reactive-form's People

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

react-reactive-form's Issues

Dirty/Pristine properties containes invalid value

If i want to check the state of input in the begining it is pristine as should be, but after I click into the input and leave it alone without modify the value, it is going to be dirty.

It should be dirty after the inited value has been changed?

I have modified one of your example repo where you can check the issue:
Example repo

can you provide one example using .onBlurChanges

this.mssqlForm.onBlurChanges.subscribe((value) => {

when i am using above pattern its throwing error like ร—
TypeError: Cannot read property 'subscribe' of undefined

please provide one example ..

How to use FormGenerator correctly with Typescript?

I was about to switch an entire project from React to Angular for the model based forms. I thought maybe I could write a React form builder and follow the patterns in Angular... then I found this plugin! Whooohooo!

My question is how to properly use the FormGenerator with Typescript.

If I follow the example in the Readme, Typescript gives me this error: Property 'userForm' does not exist on type 'UserForm'. (it is called loginForm in the Readme)
So I define it like this:

export default class UserForm extends React.Component<Iprops, Istate> {
  userForm = FormBuilder.group({
      username: ["", Validators.required]
  });

this.userForm is replaced with the dynamically generated form when this.setForm runs and everything appears to be working great. Is this the best way to write this?

full component:

import * as React from "react";
import { Validators, FormGenerator, FormBuilder } from "react-reactive-form";
// Input component
const TextInput = ({ handler, touched, hasError, meta }: any) => (
  <div>
    <input placeholder={`Enter ${meta.label}`} {...handler()} />
    <span>
      {touched && hasError("required") && `${meta.label} is required`}
    </span>
  </div>
);
// Checkbox component
const CheckBox = ({ handler }: any) => (
  <div>
    <input {...handler("checkbox")} />
  </div>
);
// Field config to configure form
const fieldConfig = {
  controls: {
    username: {
      options: {
        validators: Validators.required
      },
      render: TextInput,
      meta: { label: "Username" }
    },
    password: {
      options: {
        validators: Validators.required
      },
      render: TextInput,
      meta: { label: "Password" }
    },
    rememberMe: {
      render: CheckBox
    },
    $field_0: {
      isStatic: false,
      render: ({ invalid, meta: { handleReset } }: any) => (
        <div>
          <button type="button" onClick={handleReset}>
            Reset
          </button>
          <button type="submit" disabled={invalid}>
            Submit
          </button>
        </div>
      )
    }
  }
};
interface Iprops extends React.Props<{}> {
  handleSubmit: any;
}
interface Istate {
  signupForm: any;
}
export default class UserForm extends React.Component<Iprops, Istate> {
  userForm = FormBuilder.group({
      username: ["", Validators.required]
  });
  constructor(props: Iprops) {
    super(props);
    this.state = {
      signupForm: {}
    };
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleReset = () => {
    this.userForm.reset();
  };
  handleSubmit = (e: React.MouseEvent<HTMLFormElement>) => {
    e.preventDefault();
    console.log("Form values", this.userForm.value);
  };
  setForm = (form: any) => {
    this.userForm = form;
    this.userForm.meta = {
        handleReset: this.handleReset
    }
  };
  render() {
    return (
      <form onSubmit={this.handleSubmit} className="user-form">
        <FormGenerator onMount={this.setForm} fieldConfig={fieldConfig} />
      </form>
    );
  }
}

this.asyncValidator is not a function

When using FormBuilder, I seem to be getting 'this.asyncValidator is not a function' error,

form = FormBuilder.group({
    id: ["", customValidator, {updateOn:"blur"}]
})
model.js?3f15:638 Uncaught TypeError: this.asyncValidator is not a function
    at FormControl._runAsyncValidator (model.js?3f15:638)
    at FormControl.updateValueAndValidity (model.js?3f15:292)
    at FormControl.setValue (model.js?3f15:992)
    at Object.FormControl._this2.onChange [as change] (model.js?3f15:936)
    at HTMLInputElement.eventProxy (preact.js?10a9:97)

currently fixing it by adding a placeholder asyncValidator that doesn't do anything like so

sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
asyncValidator = (control) => {
  return sleep(1000).then(() => {
    return null
  });
};

form = FormBuilder.group({
    id: ["", customValidator, asyncValidator, {updateOn:"blur"}]
})

Is this behavior intended?

Not updating with react hooks

Describe the bug
A clear and concise description of what the bug is.
Field Group state not updating with react useState hook

To Reproduce
Steps to reproduce the behavior:

  1. Create reactive form
  2. create const [loading, setLoading] = useState(false)
  3. create button
    <Button disabled={!form.valid || loading} className="primary" onClick={submit} />
  4. change state on click
    const submit = () => {
    setLoading(true);
    }

Expected behavior
A clear and concise description of what you expected to happen.
button disabled has loading = true state
Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

Deprecation warning with React 16.9.0

Describe the bug
Getting this warning when using FieldControl with React 16.9.0: Warning: componentWillReceiveProps has been renamed (...).

To Reproduce

  1. Use FieldControl component in your app running React 16.9.0 (probably any other 16.x will show the same warning, with 17.x it will not work).

Expected behavior
No warning shown.

Desktop (please complete the following information):

  • OS: any
  • Browser: any
  • Version 1.0.31

Chances are, I will create a fix PR for this later this week.

Can't add separate Fields

Describe the bug
I use FormGenerator. And I customized my form component and used it. But when I use separate fields it's render just first one. I changed order of fields but just first one on dialog

Screenshots
image

Desktop (please complete the following information):

Additional context
how I create:

controls: {
        autosuggestion: {
            render: (control) => <AutocomplateField {...control} />,
            meta : {
                label: "some"
            }
        },
        downshift: {
            render: (control) => <IntegrationDownshift {...control}/>,
            meta: {
                label: 'downshift'
            }
        }
    }

Determine if render component has any error

First thanks so much for making this library! I haven't used Angular before but i've been really tired of the React forms with so many deps and needless boilerplate.

Anyhow, i've been struggling to find a way to determine if the "render component" has a way to determine if there is any error? My use case is to change the input border to red if any error exists, regardless of it's type.

My workaround is to use an OR clause to check all of them such as:

const TextInput = ({hasError, touched}) => {
  const hasAnyError = touched && (hasError("required") || hasError("email"));
  ...
}

Is there a way to do this in the API? I tried calling hasError with no arguments and that didn't seem to work.

Also since I have your ear, another thing I can't figure out how to do is make all of the inputs "touched" if a user submits the form. Ideally, when they hit submit on a form with errors it would show them at that time. Currently in the "form component" I have a check to see if it's valid and it currently does nothing if it's invalid or submits if it is valid.

Thanks again ๐Ÿป

in select box value is not populating when i use input box value is populating

hi @bietkul,
Small quick help,

i have one form after submitting the form am storing the data,while edit mode in select box, value is not populating when i use input box its populating.please update me what is causing issue
please find the below code.

<FieldControl
name="dbName"
strict={false}
render={({ handler, touched, hasError }: AbstractControl) => (


Database Name
<select className={form-control} {...handler()} />

                                        <div className="invalid-form">
                                            {touched
                                                && hasError('required')
                                                && 'Database name is required'}
                                        </div>
                                       
                                    </div>
                                )}
                            /> 

React 17 lifecycle support

We really need React 17 lifecycle support.

Is that something you are going to implement that quickly?

Form scrolls to top when clicking on a non-TextInput in React Native

A field has a View in it and a component which has a Touchable Opacity deep inside it. When I click on it Keyboard open, it doesn't get clicked and scrolls to top of the page. On keyboard hidden when I click on it it works as expected. Why does the form scrolls to top?

<Field
  control={addDishForm}
  render={({ get, invalid }) => (
    <KeyboardAwareScrollView
       keyboardShouldPersistTaps={true}>
         <Field
           control={get('name')}
           render={({ handler, touched, hasError }) => (
             <TextField
                {...handler()}
                ...other properties
              />
           )}
           />
           <Field
             control={get('dishType')}
             render={() => (
              <View style={styles.dietaryBoxes}>
                <DietaryBoxes dietaryInfo={value} onCheck={(s)=>this.generateArray(s)}/>
              </View>
            )}
          />
      </KeyboardAwareScrollView>
   )}
/>

DietaryBoxes component itself has several DietaryBox components and communicate with them using props. It works like this through props:
MainComponent->DietaryBoxes->DietaryBox->DietaryBoxes->MainComponent

It seems that the form thinks that an outside click was detected and some validation works and that is why it is scrolling to top. If so, is there a way to turn this feature off for a selected field (or for entire form)?

How can a default value for a list of radio buttons be set?

I'm using the form generator and I would like to render a list of radio buttons that always renders with one of the buttons checked by default. I cannot find any reference to such an option in the documentation or examples.
How can I achieve this?

Form status undefined for asyncValidator results

Describe the bug
I am using the async validator example you provided and added a listener to the form to watch status change. Works fine for sync validators but for async it first provides PENDING as expected but then, whether the validation passes or fail it returns undefined.

To Reproduce
Steps to reproduce the behavior:

  1. Create a form with async validator
  2. Add listener such as myForm.statusChanges.subscribe((value) => {
    console.log(value)

Expected behavior
I would expect VALID or INVALID

Desktop (please complete the following information):

  • Version 1.0.30

When doing an optimised build I get the following error

Hi,

I get the following error when doing an optimized build in a create-react-app.

"Failed to minify the code from this file"

    ./node_modules/react-reactive-form/src/model.js:41

Obviously works fine when just doing a "npm start" and running without any minification.

Using the following version
create-react-app 4.1.2
react 4.1.2
react.dom 4.1.2
react-scripts 4.1.2

cheers
Michael

re render FieldControl triger by state in react component

hii i have problem with fieldControll...

how to render fieldcontrol trigger by state in my own state,
example:

this.state = {
loginForm : FormBuilder.group({
username: ["", Validators.required],
nationality: ["", Validators.required],
}),
nationalityData: [] // <-- here
}

componentDidMount() {
ProductApi.product(this.props.token).then(function(product){
let data = product.data.data
let dataCbx = []

    data.forEach(value => dataCbx.push({value: value.prod_id, label: value.prod_name}));
    me.setState({nationalityData: dataCbx})

  });

}

}

render(){
console.log(this.state.nationalityData); <---- data is comming not empty array
return(
<FieldGroup ........>
render ....
<FieldControl
name="nationality"
render={(obj) => this.ComboBox(obj)}
meta={{data: this.state.nationalityData}}
/>
)
}

when axios was get data from my backend, it will be set a nationalityData but after set this, the combobox still have no data to show it. i make sure

Using the library with create-react-app

Hi,

getting issues such as below when I try the library out, installs ok but as soon as I try and import anything even just FormBuilder I get the following issue.

./node_modules/react-reactive-form/src/FieldGroup.js
Module parse failed: Unexpected token (20:6)
You may need an appropriate loader to handle this file type.
| const { strict, children, render } = this.props
| return (
| <Field
| control={this.control}
| strict={strict}

Custom components are not rendered when state changes

Describe the bug
If you use a custom component inside a FieldControl, it only renders at the beginning, but after that, if you change the state, it will keep its initial values

To Reproduce
Steps to reproduce the behavior:
Here us a stackblitz showing the issue. I am using this library
https://github.com/JedWatson/react-select
So inside the render method of the form field, I am trying to use this component instead of a html select, and it takes the default options. In componentDidMount, I have set up a setTimeout to represent a API call, and after the timeout is finished, options are loaded but the component still shows no options
https://stackblitz.com/edit/react-myx6ak

Expected behavior
I expect that when the render function runs, the custom field should re-render

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

Form config lost on second render

The form works great until I do a setState() somewhere which triggers a render. Then the form appears to completely loose it's configuration as if there were 0 fields. I noticed that the form passed from onMount the second and following times had no fields. As you can see in the code below I am setting the form to state, then once it is defined on state, I use that one to set back to this.userForm rather than what is passed from onMont. This is working, but I am not sure if this is the best way or maybe I have something setup wrong?

import {
  FormGenerator,
  AbstractControl
} from 'react-reactive-form';
export default class UserQueueForm extends React.Component<Iprops, Istate> {
  public userForm: AbstractControl;
  constructor(props: Iprops) {
    super(props);
    this.state = {
      queueForm: {}
    };
    this.handleSubmit = this.handleSubmit.bind(this);
    this.setForm = this.setForm.bind(this);
  }
  setForm = (form: AbstractControl) => {
    if (this.state.queueForm.status) {
      this.userForm = this.state.queueForm;
    } else {
      this.userForm = form;
      this.setState({ queueForm: form });
    }
    this.userForm.meta = {
      handleCancel: this.props.handleCancel,
      loading: false
    };
  };
  render() {
    return (
      <div className="loginForm">
        <form onSubmit={this.handleSubmit} className="user-form">
          <FormGenerator onMount={this.setForm} fieldConfig={fieldConfig} />
        </form>
      </div>
    );
  }

Switch component don't update touched property

Describe the bug
When we touch or change Switch value. Touched property don't change.

To Reproduce
Steps to reproduce the behavior:

  1. Change Switch value
  2. Check form control touched property
  3. It still have false value

Expected behavior
Touched value should change to true on first control touch.

Desktop (please complete the following information):

  • OS: [iOS 10.14.6]
  • Browser [chrome 76.0.3809.100]

Update Options in a select asynchronously when using FormGenerator

I put together this: https://codesandbox.io/s/kmoj4j2823
But as you see on line 92 in index.js, I don't know how to pass the updated array of options to the select.

My goal is to either update the select with the new options, or wait to add the select until the options have been received.

Perhaps something like this will work:
this.myForm.parent. setControl('nationality', [my updated control]) but I am not sure how to go about building the control for the second parameter. As well as I am not sure the setControl function is available when I am using the FormGenerator.

another idea that might work well:
use something like this.myForm.get('nationality').setMeta({options: newOptionsArray})

React native - form values are null

Describe the bug

Hi, I'm trying to use this library with React Native. I followed the steps in the Basic example section. Also I configure a React state because I need to show or hide password. But when I click in the show/hide button the form values are null, althought in the screen they are showed.

LOG Form values {"password": "hgf", "rememberMe": true, "username": "Gg"} <- Before click show/hide button
LOG Form values {"password": null, "rememberMe": false, "username": null} <- After click show/hide button

Am I skipping any steps?

To Reproduce

import React from 'react';
import { Layout, Text, Button, Icon, CheckBox, Input } from '@ui-kitten/components';
import { StyleSheet } from 'react-native';
import I18n from './../../../util/i18n/I18n';
import { FormBuilder, FieldGroup, FieldControl, Validators, FormControl } from 'react-reactive-form';
import Typography from '../../../styles/Typography';
import Global from '../../../styles/Global';

export const Login = ({ navigation }: any) => {

    const [secureTextEntry, setSecureTextEntry] = React.useState(true);

    const form = FormBuilder.group({
        username: new FormControl(null, [Validators.required]),
        password: new FormControl(null, [Validators.required]),
        rememberMe: new FormControl(false)
    });

    const handleSubmit = (event: any) => {
        event.preventDefault();
        console.log('Form values', form.value);
    }

    const renderSecureTextEntryIcon = (style: any) => (
        <Icon {...style} name={secureTextEntry ? 'eye-off' : 'eye'} />
    );

    const onSecureTextEntryIconPress = () => {
        setSecureTextEntry(!secureTextEntry);
    };

    return (
        <Layout style={{
            ...styles.pageContainer,
            ...Global.container,
            ...Global.h100
        }}>
            <Layout style={styles.fieldGroupContainer}>
                <FieldGroup
                    control={form}
                    strict={false}
                    render={({ get, invalid }) => (
                        <Layout>
                            <FieldControl
                                strict={false}
                                control={form.controls.username}
                                meta={{ label: `${I18n.t('login.form.username')}` }}
                                render={({ handler, touched, hasError, meta }: any) => (
                                    <Layout style={styles.fieldControlContainer} >
                                        <Input
                                            placeholder={`${meta.label}`}
                                            status={touched && hasError('required') ? 'danger' : 'success'}
                                            {...handler()} />
                                        {touched && hasError('required') &&
                                            (<Text status='danger'>
                                                {I18n.t('global.required', { field: meta.label })}
                                            </Text>)
                                        }
                                    </Layout>)} />
                            <FieldControl
                                strict={false}
                                control={form.controls.password}
                                meta={{ label: `${I18n.t('login.form.password')}` }}
                                render={({ handler, touched, hasError, meta }: any) => (
                                    <Layout style={styles.fieldControlContainer} >
                                        <Input
                                            placeholder={`${meta.label}`}
                                            secureTextEntry={secureTextEntry}
                                            icon={renderSecureTextEntryIcon}
                                            onIconPress={onSecureTextEntryIconPress}
                                            status={touched && hasError('required') ? 'danger' : 'success'}
                                            {...handler()} />
                                        {touched && hasError('required') &&
                                            (<Text status='danger'>
                                                {I18n.t('global.required', { field: meta.label })}
                                            </Text>)
                                        }
                                    </Layout>
                                )} />
                            <FieldControl
                                strict={false}
                                control={form.controls.rememberMe}
                                meta={{ label: `${I18n.t('login.form.rememberMe')}` }}
                                render={({ handler, touched, hasError, meta }: any) => (
                                    <CheckBox style={styles.fieldControlContainer}
                                        text={`${meta.label}`}
                                        {...handler('checkbox')}
                                    />
                                )} />
                            <Button onPress={handleSubmit} size='medium' disabled={invalid}>
                                {I18n.t('login.title')}
                            </Button>
                        </Layout>
                    )}
                />
            </Layout>
            <Layout style={{ ...styles.footerContainer }}>
                <Text style={Typography.textCenter}>{I18n.t('login.messages.dontHaveAnAccount')}</Text>
                <Button style={{ marginTop: 5 }} appearance='ghost'>
                    {I18n.t('signUp.title')}
                </Button>
            </Layout>
        </Layout>
    );
}

Expected behavior
Screenshots

Desktop (please complete the following information):

  • OS: Windows
  • Version [1.0.32]

Additional context

markAsUntouched() / markAsPrestine() doesn't update invalid/dirty on submit button.

Hello,

I'm having an issue where I want the submit button to re-disable once a form is submitted. In my submithandler I'm calling markAsUntouched() on the form, if I console.log the entire form after I can see that dirty is set to false again however the button never seems to get the updated value and stays enabled.

My render looks like this: render={({ get, invalid, dirty }) => {
And my button: <button type="submit" disabled={invalid || !dirty}>

I have no clue how to (quickly) setup a plunker (or whatever) to demonstrate the issue but I did mess around in the codesandbox.io examples and I can't seem to get it to function in there either.

Kind regards,
Jan-Jelles van Stormbroek

Validator for password not working on react native

I am working on latest react-native version. I'm trying to implement a custom validator to check if the password and password confirm are equal. The problem is that the validator function is not working.

Code::

MatchPassword(AC: AbstractControl) {
  let password = AC.get('new_password').value; // to get value in input tag
  let confirmPassword = AC.get('confirm_password').value; // to get value in input tag
  if (password !== confirmPassword) {
    AC.get('confirm_password').setErrors({ mismatch: true });
  } else {
    return null;
  }
}

changePasswordForm = FormBuilder.group({
  new_password: ['', [Validators.required]],
  confirm_password: ['', [Validators.required]],
}, {
  validator: this.MatchPassword,
});

render() {
return (
    <Fragment>
        <FieldGroup
            control={this.changePasswordForm}
            render={() => {
                return (
                    <Fragment>
                        <FieldControl
                            name="new_password"
                            render={({ handler, touched, hasError, ...props }) => (
                                <Fragment>
                                    <TextInput {...props} label="New Password" placeholder="Password" handler={handler} type="password" secureTextEntry  />
                                    {(touched && hasError('required')) && <ErrorText message="This Field Should Not Be Empty." />}
                                </Fragment>
                            )}
                        />
                        <FieldControl
                            name="confirm_password"
                            render={({ handler, touched, hasError, ...props }) => (
                                <Fragment>
                                    <TextInput {...props} label="Confirm Password" placeholder="Confirm Password" handler={handler} type="password" secureTextEntry />
                                    {(touched && hasError('required')) && <ErrorText message="This Field Should Not Be Empty." />}
                                    {(touched && hasError('mismatch')) && <ErrorText message="Password No Match!" />}
                                </Fragment>
                            )}
                        />

                        <Button onPress={() => this.handleSubmit()} variant="success" block large style={[mb0, mr15, flex1]}>Submit</Button>
                    </Fragment>
                );
            }}
        />
    </Fragment>
);
}

Please tell me how to do this?

Creating a list of checkboxes with a toggle

I've been looking through the documentation as wel as the examples and the source code, but there's something I can't figure out and that is how to have a group of checkboxes that I can all check or uncheck by the click of a button.

I have the following:

const cfg = {
  address: '',
  priority: '',
  state: FormBuilder.array([]),
};

const filterForm = FormBuilder.group(cfg);

In my component's constructor:

  this.props.statusList.forEach((status) => { // statusList is an array of objects with props 'key' and 'value'
   filterForm.get('sstate').push(FormBuilder.control(status));
  });

And in my render() function:

<FieldGroup
  control={this.filterForm}
  render={({ invalid }) => (
  <FieldArray
      render={({ controls }) => {
        return (
          <Fragment>
            <button type="button" onClick={() => { }}> // toggle button
              Alles
            </button>

            {controls.map((statusControl, index) => {
              return (
                <FieldControl
                  key={`${statusControl}${index}`} // eslint-disable-line
                  control={statusControl}
                  render={({ handler, parent, setValue, stateChanges }) => {
                    const { key, value } = handler().value;

                    return (
                      <div key={key}>
                        <input
                          id={`${name}-${key}`}
                          name="state"
                          type="checkbox"
                          value={key}
                        />

                        <label htmlFor={`${name}-${key}`}>
                          {value}
                        </label>
                      </div>
                    );
                  }}
                />
              );
            })}
          </Fragment>
        );
      }}
      name="state"
    />
  )}
/>

Two issues here:

  • when I submit the form, I don't see the value for the checked boxes; I see all the values for all of them
  • the onClick handler that I want to toggle all of the boxes doesn't seem to work with React's useState hook

How can I solve both issues mentioned? Feedback greatly appreciated.

dirty/pristine shouldn't be affected by onBlur if value didn't change

Hi,
I was following the Angular Template-driven validation to implement some kind of a Create New XXXX form.

In my implementation I noticed that the dirty/pristine were updating onBlur (click into the input and clicking outside the input) although no value was changed. This is a bit of an issue if you what to display errors only after a user changed a values.

The below implementations have the same logic:
Angular: https://stackblitz.com/edit/angular-t7dnq6-dfpyur?file=src%2Fapp%2Fname-editor%2Fname-editor.component.html
React: https://codesandbox.io/s/64rplmk3pw

I would like to submit a PR with a fix but I need a bit of direction to how the onBlur effects an AbstractControl.

Thank,
Daniel.

onBlur callback on FieldControl

Let's say I have a text input that on onFocus triggers a menu popover to be visible, and when onBlur occurs, the menu is removed.

Is there a way to use onFocus for this type of functionality? I'm not seeing onFocus support in the documentation.

It appears that updateOn: PropTypes.oneOf(['change', 'blur', 'submit']) doesn't support focus, but I thought I'd ask.

how to inject external props into the react-form .props not able to print in the form

this.props.dbList iam receiveing props from API But i am not able to print inside the FieldControl
But i can able to print in render method not in form,Can you provide some examples to inject props into FiedComtrol
<FieldGroup
control={this.mssqlForm}
render={({ get, invalid }) => (


<FieldControl
name="dbname"
render={({ handler, touched, hasError }: AbstractControl) => (

DBname:
<select className={form-control} {...handler()}>
{
this.props.dbList.map((datasource, index) => {
return (
{datasource}

);
})
}


)}
/>

To remove multiple controls from dynamic FormArray not working with removeAt

Describe the bug
To remove multiple controls from dynamic FormGroup not working with removeAt. My case i want to remove multiple FormControls from FormGroup then need to push new multiple FormControls in the same FormGroup. At that time removeAt will not worked.

If i loop through my FormGroup & try to use removeAt it will execute only one time then break the loop, also i have other logic codes below that also not executable.

I tried like below code,

control.meta.currentForm.controls['dynamicSelector']['controls'].forEach((child, index) => { child.removeAt(index); });

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

FormArrary Delete not working at index level removeAt(index) are we have any solutions to delete by index

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

Cannot call a class as a function

Describe the bug
When I use FormGenerator with a material-ui react-autosuggest, an error occurs.

To Reproduce
Steps to reproduce the behavior:

  1. index.js export { default as AutocomplateField } from './AutocomplateField';
  2. Component import {AutocomplateField } from 'app/field-components';
  3. on my imported component:
const fieldConfig = {
    controls: {
        autosuggestion: {
            render: AutocomplateField,
            meta : {
                label: "some"
            }
        }
    }
};
  1. usage: <FormGenerator fieldConfig={fieldConfig} />

Desktop (please complete the following information):

Error context

The above error occurred in the <Field> component:
    in Field (created by FieldControl)
    in FieldControl (created by Field)
    in Field (created by FieldGroup)
    in FieldGroup (created by FormGenerator)
    in FormGenerator (at ClientDialog.js:106)
    in div (created by DialogContent)
    in DialogContent (created by WithStyles(DialogContent))
    in WithStyles(DialogContent) (at ClientDialog.js:105)
    in div (created by Paper)
    in Paper (created by WithStyles(Paper))
    in WithStyles(Paper) (created by Dialog)
    in div (created by Dialog)
    in Transition (created by Slide)
    in EventListener (created by Slide)
    in Slide (created by WithTheme(Slide))
    in WithTheme(Slide) (at ClientDialog.js:11)
    in Transition (created by Dialog)
    in RootRef (created by Modal)
    in div (created by Modal)
    in Portal (created by Modal)
    in Modal (created by WithStyles(Modal))
    in WithStyles(Modal) (created by Dialog)
    in Dialog (created by WithStyles(Dialog))
    in WithStyles(Dialog) (at ClientDialog.js:95)
    in ClientDialog (created by Context.Consumer)
    in Connect(ClientDialog) (at ClientsHeader.js:56)
    in div (at ClientsHeader.js:13)
    in ClientsHeader (created by Context.Consumer)
    in Connect(ClientsHeader) (at ClientsApp.js:16)
    in MuiThemeProviderOld (at FusePageCarded.js:273)
    in div (at FusePageCarded.js:271)
    in div (at FusePageCarded.js:268)
    in div (at FusePageCarded.js:265)
    in div (at FusePageCarded.js:258)
    in FusePageCarded (created by Context.Consumer)
    in Connect(FusePageCarded) (created by WithStyles(Connect(FusePageCarded)))
    in WithStyles(Connect(FusePageCarded)) (at ClientsApp.js:10)
    in ClientsApp (at withReducer.js:18)
    in _class (created by LoadableComponent)
    in LoadableComponent (created by Context.Consumer)
    in Route (created by Context.Consumer)
    in Switch (created by Context.Consumer)
    in div (at FuseScrollbars.js:155)
    in FuseScrollbars (created by Context.Consumer)
    in Connect(FuseScrollbars) (created by Context.Consumer)
    in Route (created by withRouter(Connect(FuseScrollbars)))
    in withRouter(Connect(FuseScrollbars)) (created by WithStyles(withRouter(Connect(FuseScrollbars))))
    in WithStyles(withRouter(Connect(FuseScrollbars))) (at Layout1.js:185)
    in div (at Layout1.js:180)
    in div (at Layout1.js:174)
    in div (at Layout1.js:168)
    in div (at Layout1.js:163)
    in Layout1 (created by Context.Consumer)
    in Connect(Layout1) (created by Context.Consumer)
    in Route (created by withRouter(Connect(Layout1)))
    in withRouter(Connect(Layout1)) (created by WithStyles(withRouter(Connect(Layout1))))
    in WithStyles(withRouter(Connect(Layout1))) (at FuseLayout.js:91)
    in FuseLayout (created by Context.Consumer)
    in Connect(FuseLayout) (created by Context.Consumer)
    in Route (created by withRouter(Connect(FuseLayout)))
    in withRouter(Connect(FuseLayout)) (created by WithStyles(withRouter(Connect(FuseLayout))))
    in WithStyles(withRouter(Connect(FuseLayout))) (at App.js:37)
    in MuiThemeProviderOld (at FuseTheme.js:10)
    in FuseTheme (created by Context.Consumer)
    in Connect(FuseTheme) (created by Context.Consumer)
    in Route (created by withRouter(Connect(FuseTheme)))
    in withRouter(Connect(FuseTheme)) (at App.js:36)
    in FuseAuthorization (created by Context.Consumer)
    in Connect(FuseAuthorization) (created by Context.Consumer)
    in Route (created by withRouter(Connect(FuseAuthorization)))
    in withRouter(Connect(FuseAuthorization)) (at App.js:35)
    in Router (at App.js:34)
    in Auth (created by Context.Consumer)
    in Connect(Auth) (at App.js:33)
    in Provider (at App.js:32)
    in JssProvider (at App.js:31)
    in App (at src/index.js:13)

console.<computed> @ index.js:1437
logCapturedError @ react-dom.development.js:17848
logError @ react-dom.development.js:17884
update.callback @ react-dom.development.js:18907
callCallback @ react-dom.development.js:17072
commitUpdateEffects @ react-dom.development.js:17112
commitUpdateQueue @ react-dom.development.js:17102
commitLifeCycles @ react-dom.development.js:18140
commitAllLifeCycles @ react-dom.development.js:19642
callCallback @ react-dom.development.js:147
invokeGuardedCallbackDev @ react-dom.development.js:196
invokeGuardedCallback @ react-dom.development.js:250
commitRoot @ react-dom.development.js:19866
(anonymous) @ react-dom.development.js:21414
unstable_runWithPriority @ scheduler.development.js:255
completeRoot @ react-dom.development.js:21413
performWorkOnRoot @ react-dom.development.js:21336
performWork @ react-dom.development.js:21241
performSyncWork @ react-dom.development.js:21215
interactiveUpdates$1 @ react-dom.development.js:21500
interactiveUpdates @ react-dom.development.js:2268
dispatchInteractiveEvent @ react-dom.development.js:5086
classCallCheck.js:3 Uncaught TypeError: Cannot call a class as a function
    at _classCallCheck (classCallCheck.js:3)
    at WithStyles (withStyles.js:113)
    at Field.getComponent (react-reactive-form.es.js:2599)
    at Field.render (react-reactive-form.es.js:2610)
    at finishClassComponent (react-dom.development.js:15288)
    at updateClassComponent (react-dom.development.js:15243)
    at beginWork (react-dom.development.js:16233)
    at performUnitOfWork (react-dom.development.js:20253)
    at workLoop (react-dom.development.js:20294)
    at renderRoot (react-dom.development.js:20374)
    at performWorkOnRoot (react-dom.development.js:21331)
    at performWork (react-dom.development.js:21241)
    at performSyncWork (react-dom.development.js:21215)
    at interactiveUpdates$1 (react-dom.development.js:21500)
    at interactiveUpdates (react-dom.development.js:2268)
    at dispatchInteractiveEvent (react-dom.development.js:5086)

How to render form on state/prop change - strict = false

Describe the bug
I am trying to pass some props/state to the form. I call useEffect' to set the info but the form does not re-render. I have set strict` to false in both FieldGroup and FieldControl - I am not sure what I am missing.

I have made a sandbox here

In the sample code below which is what is in sandbox I am calling useEffect to set a variable that I want passed as the value of one of my form inputs. The default value is 'foo' and I want the form to show the updated state 'bar'. How can I achieve this?

Sample Code

import React, { useState, useEffect } from 'react'

import {
  FieldControl,
  FieldGroup,
  FormControl,
  FormGroup
} from 'react-reactive-form'

const TextInput = ({
  meta,
  handler
}) => (
<>
  <labeL>{meta.placeholder}</labeL>
  <input {...handler()} />
  </>
)

const MyForm = (props) => {
  useEffect(() => {
    setStickerStyle('bar')
  }, [])

  const [stickerStyle, setStickerStyle] = useState('foo')

  const myForm = new FormGroup({
    style: new FormControl(stickerStyle)
  })

  const handleSubmit = (e) => {
    e.preventDefault()
  }

  return (
    <>
       <form onSubmit={() => handleSubmit}>
         <h1>{stickerStyle}</h1>
         <FieldGroup
           strict={false}
           control={myForm}
           render={({ invalid, pristine, pending, value }) => (
             <div>
               <FieldControl
                 strict={false}
                 name="style"
                 render={TextInput}
                 meta={{ placeholder: 'This should be "bar" and not "foo"' }}

               />
               <pre>{JSON.stringify(value, 0, 2)}</pre>
             </div>
           )}
         />
       </form>

    </>
  )
}

export default MyForm

Version: 1.0.30"

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.