Subform example
Consider following example. It is required to enter address
information in different places in the UI. For example address
of the user, address of the order, address of the store and so on.
It is good idea to create address form and reuse it in several places.
This is where useSubform
come into play. It accepts rffFormControl
from
parent form and generate rffFormControl
for subform.
Consider following entities.
type Order = {
orderNo : number ;
carrier : string ;
deliveryAddress : {
country : string ;
state : string ;
city : string ;
zipCode : string ;
street1 : string ;
street2 ?: string | undefined ;
};
};
type Store = {
name : string
location : {
country : string ;
state : string ;
city : string ;
zipCode : string ;
street1 : string ;
street2 ?: string | undefined ;
}
}
To modify deliveryAddress.country
we can use
< Field
rffFormControl ={ rffFormControl }
rffName = "deliveryAddress.country"
rffComponent ={ Input }
/>
But this way country input will be bound to Order
and cannot be used
with address of the Store
. useSubform
solves this problem.
const addressrffFormControl = useSubform ({
rffFormControl,
rffName: 'deliveryAddress' ,
})
return (
< Field
rffFormControl ={ addressrffFormControl }
rffName = "country"
rffComponent ={ Input }
/>
)
Input for country is not bound to the Order
and can be reused
with other forms.
Example OrderForm.tsx AddressForm.tsx
const addressFormControl = useSubform ({
formControl,
name: "deliveryAddress" ,
});
// ... Other code ...
< AddressForm subFormControl ={ addressFormControl } />
import { Field, FormControl } from "react-flexible-form" ;
import * as Yup from "yup" ;
import { FC } from "react" ;
import SimpleInput from "./SimpleInput" ;
export type Address = {
country : string ;
state : string ;
city : string ;
zipCode : string ;
street1 : string ;
street2 ?: string | undefined ;
};
export const addressValidator = Yup. object ({
country: Yup. string (). required ( "Required" ),
state: Yup. string (). required ( "Required" ),
city: Yup. string (). required ( "Required" ),
zipCode: Yup. string (). required ( "Required" ),
street1: Yup. string (). required ( "Required" ),
street2: Yup. string (),
});
type Props = {
subFormControl : Omit < FormControl < Address >, "handleSubmit" >;
};
const AddressForm : FC < Props > = ({ subFormControl }) => {
return (
< div
style ={ {
width: "100%" ,
display: "grid" ,
gridTemplateRows: "repeat(4, auto)" ,
gridTemplateColumns: "auto auto" ,
gap: "10px" ,
} }
>
< Field
rffFormControl ={ subFormControl }
rffName = "country"
rffComponent ={ SimpleInput }
label = "Country"
style ={ { gridColumn: 1 , gridRow: 1 } }
/>
< Field
rffFormControl ={ subFormControl }
rffName = "state"
rffComponent ={ SimpleInput }
label = "State"
style ={ { gridColumn: 1 , gridRow: 2 } }
/>
< Field
rffFormControl ={ subFormControl }
rffName = "city"
rffComponent ={ SimpleInput }
label = "City"
style ={ { gridColumn: 1 , gridRow: 3 } }
/>
< Field
rffFormControl ={ subFormControl }
rffName = "zipCode"
rffComponent ={ SimpleInput }
label = "Zip Code"
style ={ { gridColumn: 2 , gridRow: 1 } }
/>
< Field
rffFormControl ={ subFormControl }
rffName = "street1"
rffComponent ={ SimpleInput }
label = "Street Address 1"
style ={ { gridColumn: 2 , gridRow: 2 } }
/>
< Field
rffFormControl ={ subFormControl }
rffName = "street2"
rffComponent ={ SimpleInput }
label = "Street Address 2"
style ={ { gridColumn: 2 , gridRow: 3 } }
/>
</ div >
);
};
export default AddressForm;