Clear date picker component after pressing clear button in antd - javascript

We are using antd for datepicker and moments as util. I'm stuck for a week in this ISSUE.The thing is, in the filter sidepanel,on pressing clear,all the fields should clear or set to their default values(in case of dropdown).But the date picket is not resetting.
The above picture is the Activity component and left side to its his the filter.A basic filter with API change from backend on every action event.
useEffect(()=>{
if(clearFilter){
form.resetFields()
setActivitySearchText('')
setFromDate('')
setToDate('')
setStatusSearchText('')
onStatusChange('')
setClearFilter(false)
}
},[clearFilter])
const onChangeFromDate = dateString => {
setFromDate(new Date(dateString).toISOString())
}
const onPageToDate = dateString => {
setToDate(new Date(dateString).toISOString())
}
<StyledDatePicker
allowClear={false}
format={dateFormat}
disabledDate={disabledFromDate}
placeholder={'From'}
onChange={(fromdate, dateString) =>
onChangeFromDate(fromdate, dateString)
}
showTime={{
use12Hours: true,
defaultValue: moment('00:00:00', 'HH:mm:ss'),
}}
/>
<StyledDatePicker
format={dateFormat}
disabledDate={disabledToDate}
placeholder={'To'}
onChange={(todate, dateString) => onPageToDate(todate, dateString)}
showTime={{ use12Hours: true }}
/>
The above code is the index file for all the components,we'll be passing clearfilter prop,if its true ,the filter components are set to empty.The StyledDatePicker is just wrapped in styled components of some custom width.that's it.
You can clearly see,onChangeFromDate() and onPageToDate() are the event functions happening on Change,onChange. As I said above,I'm setting the setFromDate('') and setTodate('') when clearFilter is true.
To give some context,this another main file,from which the props are passed to the others.In there,we are defining setFromDate('') and setTodate('') as,
const [fromDate, setFromDate] = useState('')
const [toDate, setToDate] = useState('')
I think I've given enough details. If need anything, request, I'm ready to give. This is a live project, I'm stuck for a week.Thanks in advance!

Related

ReactJs - MaterialTable pagination, row per page not working

I'm currently using Material-table . It displays data normally however, Pagination and Row per Page dropdown is not working. Nothing happens upon clicking, next button and selected number of rows.
See below codes:
import MaterialTable from 'material-table'
const tableIcons = {
/*table icons*/
}
function Test(){
const [data, setData] = useState([]);
const getDatas = async() => {
await axios.get('/API')
.then(response => {
setData(response.data)
}
}
const columns = [
{.....} //columns
]
return(
<div>
<MaterialTable
icons = {tableIcons}
columns = {columns}
data = {data}
title = 'List of data'
actions = {[{
//add button properties
}]}
>
</MaterialTable>
</div>
)
}
export default Test;
I'm getting the following error on console upon onload and clicking pagination buttons.
On load:
On click of next button
Please help me with this. Thank you in advance.
First of all, keep in mind that the original project was discontinued, and the new direction can be found in this repository (it's a fork of the original). There will be a lot of refactorings and breaking changes, so you might want to check them out first.
Now, on your question,
since you are working with remote data you could check out the official example on how to handle this kind of data.
If your requirements don't allow you to do this, you will need to do all the handling by yourself. That means you should provide your own implementation of the Pagination component, in which you define your own behavior of onChangePage and other callbacks.
The customisation will look something like:
Pagination: (properties: any) => {
return (
<TablePagination
{...properties}
count={currentPage.total}
onChangePage={(event: any, page: number) => {
onChangePage(page);
}}
page={currentPage.startIndex / pageSize}
/>
);
}
where total, startIndex etc. will be provided by the API you consume, along with the actual data that you show in the table.
These components overrides should be provided under the components property of the material table.

How to extend the default behaviour of a prop of a React component?

Hello I have table component taken from ant design's table and I want to change what happens when you change your current page.
function DefaultTable<T extends Entity>(props: TableProps<T>): JSX.Element {
const { pagination } = props;
const [currentPage, setCurrentPage] = useState(1);
const [currentPageSize, setCurrentPageSize] = useState<number>();
return (
<Form>
<Table
{...props}
pagination={
pagination !== false && {
onChange: e => setCurrentPage(e),
defaultCurrent: currentPage,
onShowSizeChange: (_current, newSize) => setCurrentPageSize(newSize),
pageSize: currentPageSize,
...pagination
}
}
/>
</Form>
);
}
However, when I change the page, the filters, sorters and some other configurations are also gone. I think it is because of this onChange function onChange: e => setCurrentPage(e), the default behaviour is ignored. Is there a way to extend the default onChange, and then add my current setCurrentPage(e) to it?
I've been looking on Table and Pagination implementation on antd and there is no evidence which explains why adding onChange would prevent the default behavior.
https://codesandbox.io/s/customized-filter-panel-antd4123-forked-1nwro?file=/index.js
I also have been playing around the Table example provided by antd docs, where I add a onChange handle and the filtering behavior remains the same.
Try to isolate the code and provide more info - this way we could help you better.

Changing the value of a react input component with JS doesn't fire the inputs onChange event

I have a range input that has a few things happening onChange. This works as I'd expect with manual click/drag usage. However, when I try to change the value with JavaScript, my onChange event doesn't seem to fire.
Here is my code:
const App = () => {
const [currentValue, setCurrentValue] = useState(0);
const setRangeValue = () => {
const range = document.querySelector("input");
range.value = 50;
range.dispatchEvent(new Event("change", { bubbles: true }));
};
return (
<div className="App">
<h1>Current Value: {currentValue}</h1>
<input
type="range"
min={0}
max={100}
step={10}
onChange={e => {
console.log("Change!");
setCurrentValue(+e.target.value);
}}
defaultValue={0}
/>
<button onClick={setRangeValue}>Set current value to 50</button>
</div>
);
};
And here it is (not) working in CodeSandbox:
https://codesandbox.io/s/divine-resonance-rps1n
NOTE:
Just to clarify. My actual issue comes from testing my component with jest/react testing library. The button demo is just a nice way to visualize the problem without getting into the weeds of having to duplicate all of my test stuff too.
const getMessage = (value, message) => {
const slider = getByRole('slider');
fireEvent.change(slider, { target: { value } });
slider.dispatchEvent(new Event('change', { bubbles: true }));
return getByText(message).innerHTML;
};
When the fireEvent changes the value, it doesn't run the onChange events attached to the input. Which means that getByText(message).innerHTML is incorrect, as that will only update when a set hook gets called onChange. (All of this works when manually clicking/dragging the input slider, I just can't "test" it)
Any help would be great!
The issue is that React has a virtual DOM which doesn't connect directly to the DOM. Note how the events from React are SyntheticEvents. They are not the actual event from the DOM.
https://github.com/facebook/react/issues/1152
If this is for a unit test, create a separate component for the slider and text and make sure they perform as expected separate from each other with props.
For a more in-depth article on how to specifically test a range slider, checkout https://blog.bitsrc.io/build-and-test-sliders-with-react-hooks-38aaa9422772
Best of luck to ya!

How to create a submit button in react-admin which changes appearance and behaviour depending on form data and validation

In a complex tabbed form in react-admin I need to have two submit buttons, one is the regular save button and one for altering the "status" field (advancing one workflow step) and saving the form.
The save butten should only become active if all required fields are filled by the user.
The other button changes its text depending on a "status" field in the record which contains the current workflow step, and is only active when the form validation for the current workflow step passes.
So either I need a dynamic button or several buttons which show and hide depending on the "status" field.
I think the dynamic button would be the more elegant solution.
Below you see the code I currently have, it is more or less copied from the react-admin documentation. I need to add a custom save button as well, but it is just a subset, easy to do when the AdvanceWorkflowButton works at the end.
const AdvanceWorkflowButton= ({ handleSubmitWithRedirect, ...props }) => {
const [create] = useCreate('posts');
const redirectTo = useRedirect();
const notify = useNotify();
const { basePath, redirect } = props;
const form = useForm();
// I need to set the label dynamically ... how?
// I also need sth like:
// if (validationSucceeds()) enable=true
const handleClick = useCallback(() => {
// here I need to check the current content of the "status" field.... how?
form.change('status', { "id": 2, "name": "Vorbereitung begonnen" });
handleSubmitWithRedirect('list');
}, [form]);
return <SaveButton {...props} handleSubmitWithRedirect={handleClick} />;
};
const CustomToolbar = props => (
<Toolbar {...props} >
<SaveButton
label="Speichern"
redirect="list"
submitOnEnter={true}
variant="text"
/>
<AdvanceWorkflowButton />
</Toolbar>
);
I had the exact same trouble.
Needed a button to save the form without validation, and another to save and change status with validation in place.
The code above helped me get to the answer, here are my configuration of the components necessary to achieve the desired outcome.
Set a new truthy value up in the form data as follows when the user clicks the save and next. Check the new property ('goNextStep' in our example) on the server to move the process forward.
<SaveButton
label="Save and next step"
handleSubmitWithRedirect={() => {
form.change('goNextStep', 1); // or true
props.handleSubmitWithRedirect('list');
}}
</SaveButton>
<SaveButton
label="Save only"
handleSubmitWithRedirect={() => {
form.change('validateCustom', 0); // or false
props.handleSubmitWithRedirect('list');
}}
/>
Use the validate prop on react-admin form. I could not make it work with field level validations. I had to remove every field level validation props, and implement all those in validateFunction.
Altough, you could still use the validators in your custom validation function.
const validateFunction = (values) =>{
// using our previously set custom value, which tells us which button the user clicked
let shouldValidate = values.goNextStep === 1;
// return undefined if you dont want any validation error
if (!shouldValidate) return undefined;
let errors = {};
// use built in validations something like this
var someTextFieldErrorText = required()(values.someTextField, values);
if (someTextFieldErrorText) {
errors.someTextFieldErrorText = someTextFieldErrorText;
}
// OR write plain simple validation yourself
if(!values.someTextField) {
errors.someTextField = 'Invalid property!';
}
return Object.keys(errors) ? errors : undefined;
}
Than set up tabbed form to use the previous function for validation.
<TabbedForm
validate={validateFunction}
>
...
</TabbedForm
React-admin version: 3.10.1

Materialize inputs not triggering onChange in React?

I have a Materialize input like so:
<input type="date" className="datepicker" onChange={this.props.handleChange} />
It is being correctly initialised by Materialize, but not firing onChange when the value of the datepicker changes. What am I doing wrong here? This problem seems to extend to all Materialize inputs.
On componentDidUpdate() using a prop id
var elem = document.getElementById('date');
M.Datepicker.init(elem,{
onClose:()=>{
this.state.date = elem.value;
this.setState(this.state)
}
});
I'm pretty sure this solves the caveat if you put it in your componentDidMount component.
If the select is to be re-rendered on state change, this should as well be put in componentDidUpdate
// find the select element by its ref
const el = ReactDOM.findDOMNode(this.refs.ref_to_my_select);
// initialize the select
$('select').material_select();
// register a method to fireup whenever the select changes
$(el).on('change', this.handleInputChange)
To get the value of the datepicker in materialize they provide an onSelect option when initialising the component:
var instances = M.Datepicker.init(
elems,
{
onSelect:function(){
date = instances[0].date;
console.log(date);
}
}
);
https://codepen.io/doughballs/pen/dyopgpa
Every time you pick a date, onSelect fires, in this case console.logging the chosen date.
When you close the datepicker (which is actually a modal), that's when the onChange fires, in this case logging 'onChange triggered' to the console.
that's my solution. I use useRef hook, to identify datepicker input and when onClose is fired, we can capture the object and data value, through ref var.
import React, { useEffect, useState, useRef } from "react";
import M from "materialize-css";
export default function App() {
const fromref = useRef(null); //create reference
const [date, setDate] = useState({ fromdate: "" });
const { fromdate } = date;
useEffect(() => {
let elem = document.querySelectorAll(".datepicker");
M.Datepicker.init(elem, {
firstDay: true,
format: "yyyy-mm-dd",
onClose: function() { // when onclose datepicker, we can get the value and data through the ref
console.log(fromref.current.name, fromref.current.value);
setDate({ [fromref.current.name]: fromref.current.value });
}
});
}, []);
return (
<form class="col s12">
<div class="row">
<div class="input-field col s12">
<input
name="fromdate"
type="text"
class="datepicker"
placeholder="from date"
ref={fromref} //set reference to the input
/>
</div>
</div>
</form>
);
}
If you want to get the value or other attributes you can access them from instaces variable when initialized and then check before submitting your form.
var elems = document.querySelectorAll('.timepicker');
var instances = M.Timepicker.init(elems);
Then in order to get your value before submitting your form can do as follow:
var date = instances[0].el.value;
There are two things which might be stopping the execution of expected behaviour.
If the code which you have displayed question section is from
rendered html tree, then onchnage assigment needs to be called while
assignment itself.
<input type="date" className="datepicker" onChange=this.props.handleChange(event)/>
Note: Previously browser events use to expects event callback
handlers in string format as a value.
In MaterializeCss documentation there is no mentioning of onChange event, this means there cannot be direct way to get it.
https://materializecss.com/pickers.html
It looks like you're using materialize directly in your post but if it is possible, you could try using react-materialize as it wraps all the materialize components such that it's easier to use with React. Using react-materialize would probably be the cleanest way to handle state and event changes as they provide a convenience wrapper around each materialize component.
When using the date picker from react-materialize, you'll need to pass the handleChange method into the options prop like so:
<DatePicker
options={{
...,
onSelect: this.props.handleChange
}}
/>
In the case of using the materialize date picker independently, if you could provide more details on how you're initializing the date picker input, I could provide a more relevant answer. But I'll give it a shot in the dark.
From the materialize docs it looks like you'll also have to pass back some options when you initialize it to handle a callback function when a date is selected.
I've added a JSFiddle that has a working example as well as a code snippet below, notice that when you select a date, 'hello world' is logged in the console, and the date is the first argument passed into the callback.
class Datepicker extends React.Component {
constructor(props) {
super(props)
}
handleChange(date) {
console.log('hello world', date);
}
componentDidMount() {
var elems = document.querySelectorAll('.datepicker');
var instances = M.Datepicker.init(elems, {
onSelect: this.handleChange
});
}
render() {
return (
<div>
<input type="text" className="datepicker" />
</div>
)
}
}
Live Example Fiddle
So to answer your question of how to handle events and setting the state, you just need to pass your handleChange method into the provided options configs depending on how you're using materialize date picker. In regards to integrating with a form, you could use the other callback hooks like onClose to do form validation.

Categories