How to integrate Quill (rich-text-editor) with react-final-form? - quill

How to integrate Quill (rich-text-editor) with react-final-form?

Thats it works for me
import { FC } from 'react';
import { Field } from 'react-final-form';
import ReactQuill from 'react-quill';
const FormQuill: FC<{ name: string }> = ({ name }) => (
<Field name={name}>
{({ input: { value, ...input } }) => (
<ReactQuill
value={value}
onChange={(newValue, delta, source) => {
if (source === 'user') {
input.onChange(newValue);
}
}}
/>
)}
</Field>
);
export default FormQuill;

Related

Textarea input fields in Chakra UI wont submit to react hook form

I am using nextjs (v13), react (v18) chakraUI and react hook form.
If I use Inputs (only), I can submit this form. If I change the description field to be a Textarea (from ChakraUI), the form displays on the page, but will not submit. I get no errors in the console - I can't see what's causing the issue.
Is it possible to submit data from a Textarea via react-hook-form?
import * as React from "react"
import { gql } from "#apollo/client"
import { Button, Stack, Textarea, Text } from "#chakra-ui/react"
import { useRouter } from "next/router"
import { useCreateIssueGroupMutation } from "lib/graphql"
import { useForm } from "lib/hooks/useForm"
import Yup from "lib/yup"
import { ButtonGroup } from "./ButtonGroup"
import { Form } from "./Form"
import { FormError } from "./FormError"
import { Input } from "./Input"
import { Modal } from "antd"
const _ = gql`
mutation CreateIssueGroup($data: IssueGroupInput!) {
createIssueGroup(data: $data) {
id
}
}
`
interface Props {
onClose: () => void
}
const IssueGroupSchema = Yup.object().shape({
title: Yup.string().required(),
description: Yup.string().required(),
})
export function AdminCreateIssueGroupForm(props: Props) {
const router = useRouter()
const [createIssueGroup] = useCreateIssueGroupMutation()
const defaultValues = {
title: "",
description: "",
}
const form = useForm({ defaultValues, schema: IssueGroupSchema })
const handleSubmit = (data: Yup.InferType<typeof IssueGroupSchema>) => {
return form.handler(() => createIssueGroup({ variables: { data: { ...data } } }), {
onSuccess: (res, toast) => {
toast({ description: "Issue group created" })
form.reset()
props.onClose()
},
})
}
return (
<Form {...form} onSubmit={handleSubmit}>
<Stack>
<Input name="title" label="Title" />
// this input works and allows me to submit the form
{/* <Input name="description" label="Description" /> */}
// the next 2 lines do not work. The page renders but the form does not submit
<Text mb='8px' fontWeight="medium" fontSize="sm" > Description</Text>
<Textarea name="description" rows={4} />
<FormError />
<ButtonGroup>
<Button onClick={props.onClose}>Cancel</Button>
<Button
type="submit"
isLoading={form.formState.isSubmitting}
isDisabled={form.formState.isSubmitting}
color="brand.white"
fontWeight="normal"
backgroundColor="brand.orange"
_hover={{
backgroundColor: "brand.green",
color: "brand.white",
}}
>
Create
</Button>
</ButtonGroup>
</Stack>
</Form>
)
}
My Form component has:
import * as React from "react"
import type { FieldValues, UseFormReturn } from "react-hook-form"
import { FormProvider, useFormContext } from "react-hook-form"
import { Box } from "#chakra-ui/react"
import * as Sentry from "#sentry/nextjs"
import { useToast } from "lib/hooks/useToast"
interface FormContainerProps {
onSubmit?: (values: any) => Promise<any> | any
onBlur?: (values: any) => Promise<any> | any
}
const FormContainer: React.FC<FormContainerProps> = (props) => {
const toast = useToast()
const { handleSubmit } = useFormContext()
const onSubmit = async (values: any) => {
try {
if (props.onBlur) {
return await props.onBlur(values)
}
if (props.onSubmit) {
return await props.onSubmit(values)
}
} catch (e) {
console.log(e)
Sentry.captureException(e)
toast({
title: "Application error",
description: "Something went wrong. We have been notified!",
status: "error",
})
return
}
}
return (
<Box
as="form"
w="100%"
{...(props.onSubmit && { onSubmit: handleSubmit(onSubmit) })}
{...(props.onBlur && { onBlur: handleSubmit(onSubmit) })}
>
{props.children}
</Box>
)
}
interface Props<T extends FieldValues> extends UseFormReturn<T>, FormContainerProps {
children: React.ReactNode
isDisabled?: boolean
}
export function Form<T extends FieldValues>({ onSubmit, onBlur, isDisabled, ...props }: Props<T>) {
return (
<FormProvider {...props}>
<fieldset disabled={isDisabled}>
<FormContainer {...{ onSubmit, onBlur }}>{props.children}</FormContainer>
</fieldset>
</FormProvider>
)
}
Input has:
import * as React from "react"
import { useFormContext } from "react-hook-form"
import type { InputProps } from "#chakra-ui/react";
import { FormControl, Input as CInput } from "#chakra-ui/react"
import { InputError } from "./InputError"
import { InputLabel } from "./InputLabel"
interface Props extends InputProps {
name: string
label?: string
subLabel?: string
}
export const Input = ({ label, subLabel, ...props }: Props) => {
const {
register,
formState: { errors },
} = useFormContext()
const fieldError = errors?.[props.name]
return (
<FormControl isInvalid={!!fieldError} isRequired={props.isRequired}>
<InputLabel label={label} subLabel={subLabel} name={props.name} />
<CInput {...register(props.name)} mb={0} {...props} />
<InputError error={fieldError} />
</FormControl>
)
}
Each form component connected to React Hook Form needs to receive a register or be wrapped by a Controller component. Your input component receives this by useFormContext as you mentioned:
<CInput {...register(props.name)} mb={0} {...props} />
However, TextArea component doesn't receive anything from Hook Form, in that case, you need to use the same register('').
An example of this implementation (live on CodeSandbox):
function App() {
const { register, handleSubmit } = useForm({
defaultValues: {
title: "",
description: ""
}
});
return (
<>
<form onSubmit={handleSubmit((data) => console.log(data))}>
<Heading>Welcome to Chakra + TS</Heading>
<p>Title</p>
<Input {...register("title")} />
<p>Description</p>
<Textarea {...register("description")} />
<Button type="submit">Submit</Button>
</form>
</>
);
}
Useful links:
Register
Controller
Live Example

problems with final-form in React

I have some problems with final-form. function handleSubmit don't calls anything. I checked official final-form example. I do identically that written there. But it's not working.
Here my form code:
import React, {FunctionComponent} from 'react';
import {Field, Form} from 'react-final-form';
import {IAddComponentProps} from "./interfaces";
import {EditContainer, StyledButton} from './styles';
import EditInput from "../EditInput";
const AddComponent: FunctionComponent<IAddComponentProps> = ({onSubmitForm, onEditInput}) => {
return (
<Form
onSubmit={onSubmitForm}
render={({handleSubmit}) => (
<EditContainer onSubmit={handleSubmit}>
<Field name={'addComment'}>
{({input}) => (
<EditInput {...input} onEditInput={onEditInput}/>
)}
</Field>
<StyledButton>OK</StyledButton>
</EditContainer>
)}
/>
)
};
export default AddComponent;
Here is my functions which I put into props:
const onChangeInput = (event: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(event.target.value)
}
const onSubmitAddComment = (event: React.ChangeEvent<HTMLFormElement>) => {
const newComment: ICommentsData = {
id: new Date().getMilliseconds(),
cardId: cardId,
name: author,
comment: inputValue
}
event.preventDefault();
event.target.reset()
dispatch(actions.comments.addComment({newComment}))
resetInputValue()
}
The reason of this was, that i put into onSubmit of Form function from props. When i created function inside component it started working. So new code of my form is:
import React, {FunctionComponent} from 'react';
import {Field, Form} from 'react-final-form';
import {IAddComponentProps} from "./interfaces";
import {EditContainer, StyledButton} from './styles';
import EditInput from "../EditInput";
const AddComponent: FunctionComponent<IAddComponentProps> = ({onSubmitForm, onEditInput}) => {
const onSubmit = () => {
onSubmitForm()
}
return (
<Form
onSubmit={onSubmit}
render={({handleSubmit,form}) => (
<EditContainer onSubmit={(event) => {
event.preventDefault()
handleSubmit()
form.reset()
}}>
<Field name={'addComment'}>
{({input}) => (
<EditInput {...input} onEditInput={onEditInput}/>
)}
</Field>
<StyledButton>OK</StyledButton>
</EditContainer>
)}
/>
)
};
export default AddComponent;

Ionic React-Hook-Forms

Trying to use Ionic React Hook Forms, could anyone help me with the below questions
Trying to build forms dynamically, how can we pass the properties of the ion element dynamically. in the below example i want to pass maxlength and text property (coming from backend / formFields) to IonInput Element
How to pre-populate the value to the input field
Form.tsx
import {
IonContent,
IonPage,
IonText,
IonButton,
} from "#ionic/react";
import React from "react";
import "./Form.css";
import { useForm } from "react-hook-form";
import * as globalStructre from "../Components/Content";
import Input from "../Components/Input";
import Date from "../Components/Date";
import Select from "../Components/Select";
import Textarea from "../Components/Textarea";
import Toggle from "../Components/Toggle";
const Form: React.FC = () => {
const { control, handleSubmit } = useForm();
const formFields: globalStructre.IngressProps[] = [
{
type: "Input",
name: "email",
component: ['type=\'email\''],
label: "Email",
value: "",
},
{
type: "Input",
name: "fullName",
component: ['maxlength = 60', 'type=\'text\''], //properties
label: "Full Name",
value: "test",
},
{
type: "Input",
name: "password",
component: ['maxlength = 12', 'type=\'password\''],
label: "Password",
value: "",
},
];
const registerUser = (data: any) => {
console.log("creating a new user account with: ", data);
};
const buildForm = (field: globalStructre.IngressProps, key: any) => {
let inputElement = null;
switch (field.type) {
case "Input":
inputElement = (
<Input
key={key}
name={field.name}
control={control}
component={field.component}
value={field.value}
label={field.label}
rules={field.rules}
/>
);
break;
}
return inputElement;
};
return (
<IonPage>
<IonContent>
<div className="ion-padding">
<IonText color="muted">
<h2>Create Account</h2>
</IonText>
<form onSubmit={handleSubmit(registerUser)}>
{formFields.map((field, index) =>
//<Input {...field} control={control} key={index} />
buildForm(field, index)
)}
<IonButton expand="block" type="submit" className="ion-margin-top">
Register
</IonButton>
</form>
</div>
</IonContent>
</IonPage>
);
};
export default Form;
Input.tsx
import React, { FC } from "react";
import { IonItem, IonLabel, IonInput, IonText } from "#ionic/react";
import { Controller} from "react-hook-form";
import * as globalStructre from './Content';
import './Input.css';
const Input: FC<globalStructre.IngressProps> = ({
key,
name,
control,
component,
value,
label,
rules,
errors,
}) => {
return (
<>
<IonItem >
{label && <IonLabel position="floating">{label}</IonLabel>}
<Controller
render = {({ onChange, onBlur, value }) => (
<IonInput
key={key}
value ={value}
onIonChange={onChange}
/>
)}
name={name}
control={control}
rules = {rules}
/>
</IonItem>
</>
);
};
export default Input;

Cannot read property 'focus' of null error when extracting component

I would like to implement Algolia search with Ant Design Autocomplete. But I get Cannot read property 'focus' of null error when I try to extract the SearchInput component (without extraction, i. e. when I leave it in the same file, it works fine). Here is the working code:
import React, { useState } from 'react'
import { AutoComplete, Input } from 'antd'
const SearchAutocomplete = connectAutoComplete(
({ hits, currentRefinement, refine }) => {
...
return (
<AutoComplete
options={options}
onSelect={onSelect}
onSearch={handleSearch}
open={open}
>
<Input
value={currentRefinement}
onChange={e => refine(e.currentTarget.value)}
/>
</AutoComplete>
);
}
);
But when I move Input to a separate component like this it doesn't work:
import React, { useState } from 'react'
import { AutoComplete } from 'antd'
import SearchInput from './SearchInput'
const SearchAutocomplete = connectAutoComplete(
({ hits, currentRefinement, refine }) => {
...
return (
<AutoComplete
options={options}
onSelect={onSelect}
onSearch={handleSearch}
open={open}
>
<SearchInput value={currentRefinement} onChange={e => refine(e.currentTarget.value)}/>
</AutoComplete>
);
}
);
And the SearchInput component itself:
import React from 'react'
import { Input } from 'antd'
const SearchInput = props => {
const { value, onChange} = props;
return (
<Input
value={value}
onChange={onChange}
/>
)
}
Here is the link to codesandbox with the extracted component. How can I fix this error?
Adding React.forwardRef() to SearchInput solved the issue:
const SearchInput = React.forwardRef((props, ref) => {
const { onChange } = props;
return (
<Input.Search
onChange={onChange}
ref={ref}
/>
)
})

Formik with react-naitve, using useField?

I don't use formik's Field with react-native
because doc says <Field /> will default to an HTML <input /> element
I'd like to use useField (https://stackoverflow.com/a/58650742/433570)
and wonder useField is usable with react-native?
import React from "react";
import { useField, useFormikContext } from "formik";
import DatePicker from "react-datepicker";
export const DatePickerField = ({ ...props }) => {
const { setFieldValue } = useFormikContext();
const [field] = useField(props);
return (
<DatePicker
{...field}
{...props}
selected={(field.value && new Date(field.value)) || null}
onChange={val => {
setFieldValue(field.name, val);
}}
/>
);
};

Resources