Issue with Semantic ui react calendar - reactjs

I've defined the following component to be rendered using JSX:
const TestingDate = () => {
return (
<Container>
<DateInput
clearable
clearIcon={<Icon name="remove" color="red" />}
name="date"
value="2 Apr 2020"
onChange={a => handleDateChange(a)}
/>
</Container>
);
};
However, the issue I'm having is that, in the handleDataChange, I have to keep track of the date (namely the value prop of DateInput which is imported from "semantic-ui-calendar-react", but I can't find any reasonable way of passing that to the handleDateChange function... I can see it's a super basic issue but I'm kind of stuck since it's my first time working with DateInput and the tutorial used the older style where you'd bind a callback to the DateInput as a prop.
If it helps, what I'd like to do is just call this line setDate(value) in the handleDataChange function. Thanks!

I was having the same issue and was able to resolve it by doing the following.
const TestingDate = () => {
const [date, setDate] = useState(null);
function handleDateChange(name, value) {
setDate(value)
}
return (
<Container>
<DateInput
clearable
clearIcon={<Icon name="remove" color="red" />}
name="date"
value="2 Apr 2020"
onChange={(a, {name, value}) => handleDateChange(name, value)}
/>
</Container>
);
};
I hope that helps!

Related

How to use RadixUI with React Hook Form's Controller

I'm unable to use Radix UI's select component with React Hook Form's Controller and don't understand why the following doesn't work in this CodeSandbox. Any ideas?
For example, the Radix UI documentation shows passing value and onChange props to <SelectPrimitive.Root> as well as the ref to <SelectPrimitive.Trigger>
export const Select = React.forwardRef(
({ children, ...props }, forwardedRef) => {
return (
<SelectPrimitive.Root {...props}>
<SelectPrimitive.Trigger ref={forwardedRef}>
<SelectPrimitive.Value />
...
</SelectPrimitive.Root>
How I implemented it:
const SelectItem = forwardRef(({ value, onValueChange }, forwardedRef) => {
return (
<Select.Root value={value} onValueChange={onValueChange}>
<Select.Trigger
ref={forwardedRef}
className="text-md border-solid border-2 border-slate-500 px-2"
>
...
</Select.Root>
How I pass value and onChange in WrapperSelect using RHF's Controller
<Controller
control={control}
name={name}
render={({ field: { onChange, value, ref, ...props } }) => (
<SelectItem
valueOnChange={onChange}
value={value}
forwardedRef={ref}
/>
)}
/>
I had similar problem, also with Radio button and I found out that you need to use custom <Select.Value> component with asChild prop
<Select.Value asChild>
<span>{props.value ?? "Select something..."}</span>
</Select.Value>
Here is a working sandbox: https://codesandbox.io/s/admiring-sun-xwupmz?file=/src/atoms/SelectItem.tsx

react date picker multi range with react hook form

The reason we use react hook form is that it decreases our state count and increases performance. But I didn't know how to do it when using Date range for one datepicker.
How to keep two data in one controller?
`() => {
const [startDate, setStartDate] = useState(new Date());
const [endDate, setEndDate] = useState(null);
const onChange = (dates) => {
const [start, end] = dates;
setStartDate(start);
setEndDate(end);
};
return (
<DatePicker
selected={startDate}
onChange={onChange}
startDate={startDate}
endDate={endDate}
selectsRange
inline
/>
);
};`
If this piece of code is my code, I can only capture one value with selected, but I need to return 2 values. How can I use this in the best way with the react hook form?
<Controller
name="orderDate"
control={control}
render={({ field }) => (
<DatePicker
selected={field.value}
onChange={(date) => field.onChange(date)}
selectsRange
/>
)}
/>
I've got the exact same issue last week, here is the solution...
You just need to pass (at least) the value to the "Controller function", you achieve that using only the field object.
In any case, When the DatePicker component is used for a date range, it will require a two-position vector data type, where the start and end dates are stored as a string. But if you try to manipulate and control this component via the onChange function that comes from the reack-hook-form it's gonna screw up the entire thing, because is made for a one-to-one data flux. Then the processes are done separately but the vector is still sent to the controller. Here is the code!
const [dateRange, setDateRange] = useState([null, null]);
const [startDate, endDate] = dateRange;
<Controller
//is a prop that we get back from the useForm Hook and pass into the input.
control={control}
//is how React Hook Form tracks the value of an input internally.
name={name}
//render is the most important prop; we pass a render function here.
render={({
//The function has three keys: field , fieldState, and formState.
field, // The field object exports two things (among others): value and onChange
}) => (
<>
<DatePicker
selectsRange={true}
startDate={startDate}
endDate={endDate}
onChange={(e) => {
setDateRange(e);
field.onChange(e);
}}
isClearable={true}
className="form-control"
/>
</>
)}
rules={{
required: `The ${label} field is required`,
}}
/>

React-Hook-Form Controller ignoring useEffect

I have two components, where selectBirthMonth depends on SelectBirthYear. Which is why I use useEffect, to watch the selectedYear change, so that I can change selectedMonth in case it is needed.
code sandbox
So in controller context my components look the following
<Controller
control={control}
name="selectedBirthYear"
defaultValue={years[0]}
render={({ field }) => (
<SelectBirthYear
field={field}
years={years}
value={selectedYear}
defaultValue={selectedYear}
onChange={useEffect(() => {setSelectedYear(field.value)})}
/>
)}
/>
</div>
and ...
<Controller
control={control}
name="selectedBirthMonth"
defaultValue={months[0]}
render={({ field }) => (
<SelectBirthMonth
field={field}
startYear={startYear}
selectedYear={selectedYear}
months={months}
value={selectedMonth}
defaultValue={selectedMonth}
reducedMonths={reducedMonths}
onChange={useEffect(() => setSelectedMonth(field.value))}
/>
)}
/>
SelectBirthMonth totally ignored the following code though:
const [selectedMonth, setSelectedMonth] = useState(months[0]);
const watchYearChange = () => {
if(Number(selectedYear.name) == startYear){
setSelectedMonth(reducedMonths[reducedMonths.length - 1]);
}
};
useEffect(() => watchYearChange(), [selectedYear]);
Meaning, no matter, which year is chosen, the month won't react. What do I miss?
I would recommend using a small date library like date-fns to handle date related things. It's a great package, here are the docs for it. Also it can handle i18n for you if this should be a requirement in the future.
I used it in the below CodeSandbox and also corrected a few things:
when you use RHF you don't need to setup extra state for your component as RHF will manage the form state for you.
it's much simpler if you just use one date for the whole birthdate - this way you will always have the current values for year, month and day and don't need to watch values or use extra defined state
The answer is way too easy, to be working, but it does. Several times I've been reading this post here How to change React-Hook-Form defaultValue with useEffect()?, but could't really understand, where and how do I use setValue. As I assumed, the value of my select just wasn't changing, even though I was watching the sibling state change.
So I put the setValue into the useEffect hook and the rest stayed the same:
const monthSelect = (data) => {
setSelectedMonth(months[data.id - 1]);
};
const watchYearChange = () => {
if(Number(selectedYear.name) == startYear){
setSelectedMonth(lastAvaliableMonth)
}
};
useEffect(() => setValue('selectedBirthMonth', lastAvaliableMonth), [selectedYear]);
Here are two siblings just in case:
<Controller
control={control}
name="selectedBirthYear"
defaultValue={years[0]}
render={({ field }) => (
<SelectBirthYear
field={field}
years={years}
value={selectedYear}
defaultValue={selectedYear}
onChange={useEffect(() => {setSelectedYear(field.value)})}
/>
)}
/>
... and
<Controller
control={control}
name="selectedBirthMonth"
defaultValue={selectedMonth}
render={({ field }) => (
< SelectBirthMonth
field={field}
startYear={startYear}
selectedYear={selectedYear}
months={months}
value={selectedMonth}
reducedMonths={reducedMonths}
onChange={useEffect(() => monthSelect(field.value)), [selectedMonth]}/>
)}
/>
If this solution somehow is not good, please let me know in the comments. I am a total beginner.

How can we set default value for React RRule Generator in react-admin?

I am using react-admin and react-rrule-generator (https://github.com/Fafruch/react-rrule-generator). Create / Adding records is working fine while using rrule widget. But whenever I try to edit a record, the widget should have its values automatically filled based on the record's values. But the value is always the default one provided by the widget itself. Here is my code:
main_file.jsx
export const JobCreate = (props) => {
return (
<Create {...props}>
<SimpleForm>
<CustomRRuleInput name="recurrency" label="Recurrency" />
</SimpleForm>
</Create>
)
}
recurrency_field.jsx
export const CustomRRuleInput = (props) => {
const {
input: { onChange },
meta: { touched, error },
} = useInput(props)
return (
<Labeled label={props.label}>
<RRuleGenerator
onChange={onChange}
name={props.name}
/>
</Labeled>
)
}
If I add value={props.record.recurrency} in RRuleGenerator component, I can't change values because I kind of fixed / hardcoded its value which is constant even if I try to change them. If this widget had a prop called defaultValue then it would have worked out!
How can I achieve this?
If you check closely the documentation's Inputs/Writing your own input part you will notice that custom input compoenents using either useField or useInput hooks still receive the source prop which is passed inside the input as part of the hook parameters.
Try this:
Inside main_file.jsx
<CustomRRuleInput source="recurrency" label="Recurrency" />
Inside recurrency_field.jsx
const {
input: { name, onChange },
meta: { touched, error },
} = useInput(props)
return (
<Labeled label={props.label}>
<RRuleGenerator
onChange={onChange}
name={name}
/>
</Labeled>
)
Never mind I did it! I can use this for creation as well as updating records. I also used rrule library for converting rrule to human readable text which gets displayed in TextInput field just below RRule widget. The text dynamically changes when you change data in RRule widget.
recurrency_field.jsx
import RRuleGenerator from "react-rrule-generator"
import React, { useState } from "react"
import { useInput, Labeled, TextInput } from "react-admin"
import { rrulestr } from "rrule"
export const CustomRRuleInput = (props) => {
const record = props.record
const {
input: { onChange },
} = useInput(props)
const [state, setState] = useState(record[props.name])
return (
<>
<Labeled label={props.label}>
<RRuleGenerator
onChange={(val) => {
setState(val)
onChange(val)
}}
value={state}
name={props.name}
/>
</Labeled>
<TextInput
fullWidth
disabled
label={"RRule Text"}
value={state ? rrulestr(state).toText() : ""}
/>
</>
)
}
main_file.jsx
<CustomRRuleInput name="recurrency" label="Recurrency(r rule)" />

How to use custom Input with Formik in React?

I'm trying to use DatePicker within Formik. But when I click DatePicker's date its form value is not changed. Instead, I got this error:
Uncaught TypeError: e.persist is not a function
at Formik._this.handleChange (formik.es6.js:5960)
I shortify code, the code is below
const SomeComponent = () => (
<Formik
render={({
values,
handleSubmit,
handleChange,
setFieldValue
}) => {
return (
<div>
<form onSubmit={handleSubmit}>
<DatePicker
name={'joinedAt'}
value={values['joinedAt']}
onChange={handleChange}
/>
</form>
</div>
)
}}
/>
)
I googled few documents, https://github.com/jaredpalmer/formik/issues/187 and https://github.com/jaredpalmer/formik/issues/86
So I tried like below, but it's not working.
...setFieldValue
<DatePicker
name={'joinedAt'}
value={values['joinedAt']}
onChange={setFieldValue}
/>
I resolve this like
<DatePicker
name={'joinedAt'}
value={values['joinedAt']}
onChange={e => setFieldValue('joinedAt', e)}
/>
Update on 2020-03-08:
You can use e.target.value on setFieldValue's second prop, depends on your custom input design. Thanks to Brandon.
If you have deeper nesting, you should use Formik Field.
Example:
<Formik
validationSchema={schema}
initialValues={initialValues}
onSubmit={(values, actions) => {}}
>
<Field name="colors" component={ColorsEditor} colors={colorArray}/>
</Formik>
const ColorsEditor = ({ field, colors, form, ...props }) => {
return (
<div>
<Button onClick={() => form.setFieldValue('colors', "myValue")}>
</Button>
</div>
)
}
So the Field component already include the form, where live the setFieldValue that you can use where you need. It also include the errors and needed fields for additional customization.
For html primitive input fields handleChange works like a charm, but for custom components, you've to use setFieldValue to change the value imperatively.
onChange={e => setFieldValue('joinedAt', e)}
The accepted answer didn't work for me and didn't show the selected date. It has been almost a year so there might be some changes with the implementation. Though this can be fix by using toDateString() like this
<DatePicker
name={'joinedAt'}
value={values['joinedAt']}
onChange={e => setFieldValue('joinedAt', e.toDateString())}
/>
The Formik solution for this is the useField() method. You may need to create a wrapper for components like DatePicker that you may not have source access to.
The documentation provides an example:
const MyTextField = ({ label, ...props }) => {
const [field, meta, helpers] = useField(props);
return (
<>
<label>
{label}
<input {...field} {...props} />
</label>
{meta.touched && meta.error ? (
<div className="error">{meta.error}</div>
) : null}
</>
);
};
In short, the method takes in the custom props which describe the field. Then you can expand the assigned field value and props in your custom field.
https://github.com/jaredpalmer/formik/issues/692
you need to set value manually if you are using setFieldValue method

Resources