React-infinite-calendar range selection - reactjs

I am facing issues with onSelect event for range selection in react-infinite-calendar. Can any one suggest me with answers ? I want to select start date and end date and get those values to pass to the state.

JSX
<InfiniteCalendar
Component={withRange(Calendar)}
height={350}
min={new Date(2017,8,1)}
selected={this.state.selectedDates}
layout={'portrait'}
width={'100%'}
onSelect={this.onCalendarSelect}
/>
onCalendarSelectCode
onCalendarSelect = (e) => {
if (e.eventType === 3) {
this.setState({ selectedDates: {
start: e.start,
end: e.end,
} });
}
}
on select with range functionality will return an object with start, end, and eventType. Event type of 3 will indicate user has selected a start and end. You can then set this to state.

Related

How to handel event onChange of react-date-range (Date range) when only select start date or end date

I have a component DateRange using react-date-range ,
Import :
import { Range, DateRange, RangeKeyDict } from 'react-date-range';
import 'react-date-range/dist/styles.css';
import 'react-date-range/dist/theme/default.css';
Default value :
const [dateRangeValue, setDateRangeValue] = useState<Range>({
startDate: new Date(),
endDate: new Date(),
});
Fuction :
const handelOnchange = (itemRespon: Range): void => {
console.log('itemRespon,', itemRespon);
//Display start end date which was chosen
renderFooteDate(itemRespon);
//Set new date range value
setDateRangeValue(itemRespon);
//CallBackParrent to give data back
};
Component :
<DateRange
className={style.dateRangeWrapper}
editableDateInputs={true}
onChange={(item: RangeKeyDict): void => handelOnchange(item.selection)}
moveRangeOnFirstSelection={false}
ranges={[{ ...dateRangeValue, key: 'selection' }]}
months={2}
direction="horizontal"
/>
Picture :
Date
2.I hope i can get value when ever i chose only start date or end date , but currently it only active onChange event when i click both start and end date. I do not always need both start and end , sometimes i just need 1 of them is enough.
I tried to reproduce the error, but it works fine for me.
Please see example.
The only thing you have to do is to press Enter after changing the date, then the changes will be applied.

Checkmark group of checkboxes based on array values

Forgive me there are a lot of questions asking this same thing but from over 10+ years ago.
Is there any way to checkmark a group of checkboxes based on an array in React? I have an array saved within state (stepThree) that I need to pulldown when a user returns to this screen within a multistep form. I'm looking for a way that the values within that array become/stay checked upon return to that screen so it shows the user their previous selections.
Current set-up explained below
State is opened with empty checkedBox array and stepThree initialized to pull responses later. checkedBox is eventually cloned into stepThree.
this.state = {
checkedBox: [],
stepThree: this.props.getStore().stepThree,
};
Boxes that are checked by the user are added to checkedBox array or removed if unchecked.
handleCheckboxChange = (event) =>{
const isChecked = event.target.value; //Grab the value of the clicked checkbox
if (this.state.checkedBox.includes(isChecked)) {
// If the checked value already exists in the array remove it
} else {
// If it does not exist, add it
}
}
Validate and store the completed array on clicking next
if (Object.keys(validateNewInput).every((k) => { return validateNewInput[k] === true })) {
if (this.props.getStore().stepThreeObjects != this.state.checkedBox) { // only update store of something changed
this.props.updateStore({
// Store the values of checkedBox inside stepThree and run updateStore to save the responses
});
} else {
// Return an error
}
Sample checkbox
<label className="choice-contain">
<span>Checkbox Sample</span>
<input
value="Checkbox Sample"
name="Question 3"
type="checkbox"
onChange={this.handleCheckboxChange}
/>
</label>
I've tried to create a persistCheckmark function that pulls the values of the array from stepThree and then does a comparison returning true/false like I do in the handler but since this is not an event I can't figure out how to trigger that function on return to the step.
Currently when returning to the step nothing is checked again and I believe that has to do with checkedBox being initiated as empty.
persistCheckmark(event) {
const isChecked = event.target.value; //Grab the value of the clicked checkbox
if (this.state.stepThree.includes(isChecked)) {
return true;
} else {
return false
}
}
Figured it out thanks to an old post here: How do I set a group of checkboxes using values?
Just updated the filter for when the component mounts
componentDidMount() {
if (this.state.stepThree != undefined) {
var isChecked = this.state.stepThree
$('input[type="checkbox"]').filter(function() {
return $.inArray(this.value, isChecked) != -1;
}).prop('checked', true);
} else { return }
}
and then added a ternary in the state initiation to check the storage and copy it over so it doesn't initialize as empty every time.
checkedBox: this.props.getStore().stepThree != undefined ? this.props.getStore().stepThree : [],

Conditional dropdowns with react-select in react-final-form initialized from the state

I'm using react-select and react-final-form for conditional dropdowns, where options for the second select are provided by a <PickOptions/> component based on the value of the first select (thanks to this SO answer).
Here is the component:
/** Changes options and clears field B when field A changes */
const PickOptions = ({ a, b, optionsMap, children }) => {
const aField = useField(a, { subscription: { value: 1 } });
const bField = useField(b, { subscription: {} });
const aValue = aField.input.value.value;
const changeB = bField.input.onChange;
const [options, setOptions] = React.useState(optionsMap[aValue]);
React.useEffect(() => {
changeB(undefined); // clear B
setOptions(optionsMap[aValue]);
}, [aValue, changeB, optionsMap]);
return children(options || []);
};
It clears the second select when the value of the first one changes by changeB(undefined). I've also set the second select to the first option in an array by passing initialValue. As I need to initialize the values from the state, I ended up with the following code:
initialValue={
this.state.data.options[index] &&
this.state.data.options[index].secondOption
? this.state.data.options[index]
.secondOption
: options.filter(
option => option.type === "option"
)[0]
}
But it doesn't work. Initial values from the state are not being passed to the fields rendered by <PickOptions/>. If I delete changeB(undefined) from the component, the values are passed but then the input value of the second select is not updated, when the value of the first select changes (even though the options have been updated). Here is the link to my codesandbox.
How can I fix it?
I was able to get this to work by taking everything that is mapped by the fields.map() section and wrapping it in it's own component to ensure that each of them have separate states. Then I just put the changeB(undefined) function in the return call of the useEffect hook to clear the secondary selects after the user selects a different option for the first select like so:
React.useEffect(() => {
setOptions(optionsMap[aValue]);
return function cleanup() {
changeB(undefined) // clear B
};
}, [aValue, changeB, optionsMap]);
You can see how it works in this sandbox: React Final Form - Clear Secondary Selects.
To change the secondary select fields, you will need to pass an extra prop to PickOptions for the type of option the array corresponds to. I also subscribe and keep track of the previous bValue to check if it exists in the current bValueSet array. If it exists, we leave it alone, otherwise we update it with the first value in its corresponding optionType array.
// subscibe to keep track of previous bValue
const bFieldSubscription = useField(b, { subscription: { value: 1 } })
const bValue = bFieldSubscription.input.value.value
React.useEffect(() => {
setOptions(optionsMap[aValue]);
if (optionsMap[aValue]) {
// set of bValues defined in array
const bValueSet = optionsMap[aValue].filter(x => x.type === optionType);
// if the previous bValue does not exist in the current bValueSet then changeB
if (!bValueSet.some(x => x.value === bValue)) {
changeB(bValueSet[0]); // change B
}
}
}, [aValue, changeB, optionsMap]);
Here is the sandbox for that method: React Final Form - Update Secondary Selects.
I also changed your class component into a functional because it was easier for me to see and test what was going on but it this method should also work with your class component.
Based on the previous answer I ended up with the following code in my component:
// subscibe to keep track of aField has been changed
const aFieldSubscription = useField(a, { subscription: { dirty: 1 } });
React.useEffect(() => {
setOptions(optionsMap[aValue]);
if (optionsMap[aValue]) {
// set of bValues defined in array
const bValueSet = optionsMap[aValue].filter(x => x.type === optionType);
if (aFieldSubscription.meta.dirty) {
changeB(bValueSet[0]); // change B
}
}
}, [aValue, changeB, optionsMap]);
This way it checks whether the aField has been changed by the user, and if it's true it sets the value of the bField to the first option in an array.

React (Reakit): How to ask for confirmation, when toggling a checkbox?

I'm wondering, if there's a way to ask for confirmation with Reakit's checkbox. I'm using Reakit, since I found a quick way to get it to read database's boolean information, but I welcome other methods too!
I'm used to doing confirmations with buttons with async and window.confirm:
<button onClick={async hiStackOverflow => {
if (window.confirm("Want to do this?")) {
// saving to database here
}
}}>
But I didn't figure out how to do it with a checkbox. In short, I want for the page to confirm (and then save to database), when the user toggles on/off the checkbox.
// personData = database table, with boolean "recurring"
// row = which entity in a table we are talking about
function CheckboxThing ({ row, personData }) {
const checkbox = useCheckboxState({state: personData[row].recurring});
return (
<div className="checkbox-admin-other">
<Checkbox
{...checkbox}
// what here?? onClick or something?
/>
</div>
);
}
Reakit's checkbox can be used like this:
const toggle = () => setChecked(!checked);
return <Checkbox checked={checked} onChange={toggle} />;
This means that the checkbox will be checked if the variable 'checked', which needs to be put in the state of your React component, is true and that the method called 'toggle' will be called when the user toggles the checkbox. In that method, you can put the code which will show the Confirmation Prompt and then change checked if user clicked 'Yes' or leave it as it is if they check 'No'.
You can "observe" changes on checkbox.state using React Hooks:
function CheckboxThing({ row, personData }) {
const checkbox = useCheckboxState({ state: personData[row].recurring });
React.useEffect(() => {
// checking if state has changed
if (checkbox.state !== personData[row].recurring) {
if (window.confirm("Want to do this?")) {
// saving to database here
} else {
// revert checkbox state otherwise
checkbox.setState(!checkbox.state);
}
}
}, [checkbox.state, checkbox.setState, personData[row].recurring]);
return (
<div className="checkbox-admin-other">
<Checkbox {...checkbox} />
</div>
);
}
With React.useEffect, the user will see the checkbox checked before window.confirm opens. But you can use React.useLayoutEffect instead if you want it to open before checkbox state changes on the UI.
After coding around a little while, I found the solution! It turns out, you can put async inside Reakit Checkbox. Thanks to Tomislav and Diego, their answers helped me try different things and get it clean!
Here's the full function:
// admin can edit the right to join back to the queue after getting to the front
function RecurringBox ({ row, personData }) {
// sets the original values
const checkbox = useCheckboxState({state: personData[row - 1].recurring});
return (
<Checkbox {...checkbox} onChange={async checkboxSwitch => {
if (window.confirm("Change it?")) {
checkboxSwitch.persist();
// saving it to the database
await put(`${process.env.API_PATH}/person`,
{
"id": personData[row - 1].id,
"name": personData[row - 1].name,
"recurring": checkboxSwitch.target.checked
});
reload(`${process.env.API_PATH}/person`);
} else {
return null;
}
}}/>
);
}

How to update item in array using react?

Could you please tell me how to update item in array using react? I make a dynamic list using add button. In generated Item I have two button update and delete.
On click of update button I change the text of add button to update and fill the selected value in input field. Now when I click update button I want to update the selected item.
Here is my code
https://plnkr.co/edit/bpSGPLLoDZcofV4DYxPe?p=preview
addName() {
if (this.state.username !== '') {
if (this.state.btnText === 'add') {
this.props.add(this.state.username)
} else if (this.state.btnText === 'update') {
this.props.updateItem(this.state.username)
}
this.setState({
username: '',
btnText: 'add'
})
}
}
delete(item) {
this.props.deleteItem(item)
}
update(item){
this.setState({
username : item,
btnText:'update'
})
}
You need to pass the updated item name and the indexof the item to the update case in the reducer. Then just use splice to update the new value
Updated the plunkr. Check it here
case 'UPDATE_ITEM':
let newList = state.slice()
newList.splice(action.payload.index, 1, action.payload.item)
return newList;

Resources