Difference in Months between two dates in React.js using KeyboardDatePicker - html

const Index = (props) => {
const [selectedDate, setSelectedDate] = useState(
new Date("2014-08-18T21:11:54")
);
const handleDateChange = (date) => {
setSelectedDate(date);
};
return (
<div>
//first date picker
<MuiPickersUtilsProvider
utils={DateFnsUtils}
// className={classes.formControlNew}
style={{ width: "100%" }}
>
<KeyboardDatePicker
style={{ marginLeft: "5%", width: "91%" }}
margin="normal"
id="date-picker-dialog1"
label="Start Date"
format="MM/dd/yyyy"
value={selectedDate}
onChange={handleDateChange}
KeyboardButtonProps={{
"aria-label": "change date",
}}
/>
</MuiPickersUtilsProvider>
// second date picker
<MuiPickersUtilsProvider
utils={DateFnsUtils}
style={{ width: "100%" }}
>
<KeyboardDatePicker
style={{ marginLeft: "5%", width: "91%" }}
margin="normal"
id="date-picker-dialog2"
label="End Date"
format="MM/dd/yyyy"
value={selectedDate}
onChange={handleDateChange}
KeyboardButtonProps={{
"aria-label": "change date",
}}
/>
</MuiPickersUtilsProvider>
</div>
);
};
There are two date pickers using which I am taking two dates from user .In which first date is start date & second is End Date . I want to calculate difference between these two dates in months.How should i get the difference in months ? What are the calculations need to be done in Reactjs .

There are a few things missing here.
You are going to want to duplicate selectedDate and handleDateChange so that you can keep track of the two dates separately. Perhaps selectedStartDate and selectedEndDate
To calculate the difference, I would recommend using the moment npm package with syntax similar to:
const months = moment.duration(moment(selectedEndDate).diff(moment(selectedStartDate))).asMinutes()

Related

Form mapped over with 2 data sets, how do I access a property from set 1 whilst editing set 2? (React JS)

I have a form that, in total, has 5 columns per row. The first 3 columns are readOnly and mapped with data from from MySQL table_1, the last 2 columns are editable and mapped with data from MySQL table_2 (NodeJS API). The number of rows in the form is dictated by the number of rows returned from a SELECT query against table_1.
Here's an example of a single table_1 row:
[{pacesetterID: 100, startDate: "15/11/2022", endDate: "19/11/2022", objectives: "Make a sandwich"}]
Here's an example of a single table_2 row:
[{pacesetterID: 100, studyTime: "50", completionStatus: "In Progress"}]
Here's a photo for visual reference
The data maps perfectly fine, but the moment I begin trying to edit the last 2 columns of each row, the console displays errors like this 6 ways from Sunday.
TypeError: undefined is not an object (evaluating 'list[index][name] = value')
What I am trying to achieve is essentially a new array generated containing all edited columns including the 'pacesetterID' for that specific edited row. For example, if the the first three rows were edited I need an array that looks like this (to post to API):
[{ pacesetterID: 100, studyTime: "50", completionStatus: "Completed" }, { pacesetterID: 101, studyTime: "13", completionStatus: "In Progress" }, { pacesetterID: 102, studyTime: "50", completionStatus: "In Progress" }];
Here is the code for the change handler, the state, as well as the markup for the form itself.
const PacesetterEntry = () => {
const [pacesetterRows, setPacesetterRows] = useState([]); //table_1
const [pacesetterList, setPacesetterList] = useState([
{
pacesetterID: "",
studyTime: "",
completionStatus: "",
},
]); //table_2
const handlePacesetterChange = (e, index) => {
const { name, value } = e.target;
const list = [...pacesetterList];
list[index][name] = value;
setPacesetterList(list);
};
useEffect(() => {
const fetchData = async () => {
//Axios get query...
setPacesetterRows(results.data[0]);
setPacesetterList(results.data[1]);
};
fetchData();
}, [classID, studentID, token]);
return (
<>
<CRow>
<CCol xs>
<CCard className="mb-4">
<CCardHeader>Update Pacesetter Entries</CCardHeader>
<CCardBody>
<form method="post" className="mb-0">
<div className="row">
<div className="col-md-6">
<CFormSelect
className="pointer"
onChange={(e) => setClassID(e.target.value)}
value={classID}
>
<option value="">Select Your Class</option>
{classOption.map((c) => (
<option key={c.classID} value={c.classID}>
{c.subjectTitle} {c.subjectLevel} ({c.syllabusCode} -{" "}
{c.classIdentifier})
</option>
))}
</CFormSelect>
</div>
</div>
<br />
<div className="row">
<div className="col-md-2">
<CButton
variant="outline"
color="danger"
size="sm"
onClick={() => {
setClassID("");
}}
>
Clear Class Selection
</CButton>
</div>
</div>
<br />
{pacesetterRows.map((s, index) => (
<div className="row align-items-center mb-3" key={index}>
<div className="col-md-2">
<CFormInput
readOnly
value={s.startDate}
name="startDate"
placeholder="Start Date 'DD/MM/YYYY'"
></CFormInput>
<CFormInput
hidden
value={s.pacesetterID}
name="pacesetterID"
></CFormInput>
</div>
<div className="col-md-2">
<CFormInput
readOnly
value={s.endDate}
name="endDate"
placeholder="End Date 'DD/MM/YYYY'"
></CFormInput>
</div>
<div className="col-md-4">
<CFormTextarea
disabled
value={s.objectives}
id="exampleFormControlTextarea1"
rows="1"
name="objectives"
placeholder="Objective for the week..."
></CFormTextarea>
</div>
{pacesetterRows.map((p, index) => (
<>
<div className="col-md-2">
<CFormInput
onChange={(e) => handlePacesetterChange(e, index)}
value={p.studyTime}
name="studyTime"
placeholder="Study Time (Minutes)"
></CFormInput>
</div>
<div className="col-md-2">
<CFormSelect
className="pointer"
name="completionStatus"
onChange={(e) => handlePacesetterChange(e, index)}
value={p.completionStatus}
>
<option value="">Select Status</option>
<option value="Not Yet Started">
Not Yet Started
</option>
<option value="In Progress">In Progress</option>
<option value="Completed">Completed</option>
</CFormSelect>
</div>
</>
))}
</div>
))}
</form>
</CCardBody>
</CCard>
</CCol>
</CRow>
</>
);
};
Note: Not all rows in table_2 are matched in table_1, so that throws a MySQL join query out of the window

Mui DatePicker change date format

I am trying to customise the mui DatePicker. I want the date format to be as follows: Day, DD Month.
example: Monday, 10 September
here is my code:
<LocalizationProvider dateAdapter={AdapterDateFns} locale={frLocale}>
<Stack spacing={3}>
<ThemeProvider theme={calendarTheme}>
<DatePicker
disabled={false}
//the current format
inputFormat="MM/dd/yyyy"
leftArrowButtonText={t("notification.previous_month")}
rightArrowButtonText={t("notification.next_month")}
minDate={today}
InputProps={{
classes: {
notchedOutline: classes.noBorder,
root: classes.reverse,
},
}}
components={{
OpenPickerIcon: Table,
SwitchViewIcon: ArrowDown,
}}
value={value}
onChange={handlechange}
renderInput={(params: any) => (
<TextField
style={{
color: "red",
}}
{...params}
/>
)}
/>
</ThemeProvider>
</Stack>
</LocalizationProvider>
You need to use fromat like format="EEEE, MM MMMM":
<DesktopDatePicker
label="Date desktop"
inputFormat="EEEE, MM MMMM"
openTo={"day"}
value={value}
onChange={handleChange}
renderInput={(params) => <TextField {...params} />}
/>

why my state situation does not change when choose date in select opt

//=> my state
const [date, setDate] = useState({ year: "", month: "", full: "" });
///=> here is to change state situation after month changed
else if (target.name === "cardMonth") {
target.value = formatMonthDate(target.value);
setDate({ ...date, month: target.value });
}
//=> here is my select option area to select date
<div className="form-group">
<div className="input-group mb-3">
<select
className="custom-select"
name="cardMonth"
onChange={(e) => handleInputChange(e)}
onFocus={(e) => handleInputFocus(e)}
>
{months.map((month) => (
<option value={month} key={month}>
{month}
</option>
))}
</select>
</div>
</div>
the problem is when i chose a month for the first time , then it can't appear in state but when i chose a new date then my state takes first state. shortly state situation follow changes one step back. for example : ı chose january first time nd it is not appeaar in my state . later ı choose february and ı see january in state not february . if i choose a new one then i ll see january and february only not new one. it goes like this and i almost spent one day for this.

React with Kendo-ui Grid - Wrong column header

I have a React application using redux as state manager. In this application we are deciding to use Kendo Ui grids. The first test is Ok but we noticed that the columns are totally wrong. We define only 5 Columns to be displayed in the table but we noticed that all the columns from the json object get displayed. For example in the render method I have this code:
render() {
return (
<div>
<Grid
style={{ height: '400px' }}
data={this.state.gridData}
>
<Column field="ProductID" title="ID" width="40px" />
<Column field="ProductName" title="Name" width="250px" />
<Column field="Category.CategoryName" title="CategoryName" />
<Column field="UnitPrice" title="Price" width="80px" />
<Column field="UnitsInStock" title="In stock" width="80px" />
</Grid>
</div>
);
}
which should show only:
ID | Name | CategoryName | Price | In stock
but what it renders are those headers:
ProductID | ProductName | SupplierID | CategoryID | UnitPrice | UnitsInStock
which are the from the json object directly:
"ProductID " : 1,
"ProductName" : "Chai",
"SupplierID" : 1,
"CategoryID" : 1,
"UnitPrice" : 18.0000,
"UnitsInStock" : 39
In other words, no matter which columns I define (as <Column /> tag), the grid shows always the json field as column headers.
Following libs are imported:
import { Grid, GridColumn as Column, GridCell } from '#progress/kendo-react-grid';
I'm using exactly the exmaple from this page:
https://www.telerik.com/kendo-react-ui/components/grid/
There is no error in the console, so it is hard to find whats going on.
Any idea?
Update:
I added this console.log statement and i see that the columns are empty:
constructor(props: IProps) {
super(props);
this.state = { producuts: [{ ProductID: 'Cindy', ProductName: 'Jones', UnitPrice: 'cindy.jones#telerik.com' }]
};
this.grid = null;
}
render() {
return (
<div>
<Grid
data={this.state.producuts}
reorderable={true}
ref={(g) => { this.grid = g; }}
>
<GridColumn field="ProductID" title="ID" />
<GridColumn field="ProductName" title="Name" />
</Grid>
<button onClick={() => {
console.log(this.grid);
console.log(JSON.stringify(this.grid.columns));
}}>
log current properties into browser console.
</button>
</div>
);
}
This line console.log(JSON.stringify(this.grid.columns)) has always empty array result []
Although the headers should be:
ID | Name
but they appear like this:
I recently had the same problem. We are using 'react-hot-loader' which leads to your described error.
In the source code of the grid is a type comparison:
this.initColumns(children.filter(function (child) { return child && child.type === GridColumn; }));
When using react-hot-loader a Column is not of type GridColumn, but of type Proxycomponent. So the type check fails and the grid renders the default columns.
Workaround:
reactHotLoader.disableProxyCreation = true;
var grid = (<KendoGrid data={ { data: this.state.Products, total: 1} }
pageable={true} >
<KendoColumn field="ProductName" title="Product Name" />
<KendoColumn field="UnitPrice" title="Unit Price" format="{0:c}" width="120px" />
<KendoColumn field="UnitsInStock" title="Units In Stock" width="120px" />
<KendoColumn field="Discontinued" width="120px" />
</KendoGrid>);
reactHotLoader.disableProxyCreation = false;
Disabling the proxy creations solves the problem, but this workaround is quite dirty.
We disabled react-hot-loader in our project to solve this issue.

In Angular 4, how to dynamically set min date and max date in date picker?

I am trying to show disable past dates from current date, meaning user should not select past date from date picker.
Below is the code I am using to set min date in Datepicker
Component.html
<input type="text" formControlName="eventStart" [(ngModel)]="event_start" class="form-control pull-right"
id="event_start" required placeholder='{{ "EVENT.FORM.START_DATE" | translate }}'>
<input type="text" formControlName="eventEnd" [(ngModel)]="event_end" class="form-control pull-right"
id="event_end" placeholder='{{ "EVENT.FORM.END_DATE" | translate }}'>
Component.ts
this.datePicker = jQuery('#event_start').datepicker({
autoclose: true,
orientation: 'left bottom',
});
this.datePicker = jQuery('#event_end').datepicker({
autoclose: true,
orientation: 'left bottom',
});
You're setting this.datePicker twice:
jQuery('#event_start')
jQuery('#event_end')
I suggest you to refactor your code like this:
const datePickerConfig = {
autoclose: true,
orientation: 'left bottom',
};
this.startDatePicker = document.querySelector('#event_start').datepicker(datePickerConfig);
this.endDatePicker = document.querySelector('#event_end').datepicker(datePickerConfig);
In order to help you efficiently, please tell which date picker library you're using.
You can use ngb-datepicker from angular bootstrap.
Modify your component.ts in following way,
now: Date = new Date();
minDate: any;
maxDate: any;
//If you want to disable past dates from current date, you can set mindate to current date.
this.minDate = { year: this.now.getFullYear(), month: this.now.getMonth() + 1, day: this.now.getDate() };
//If you want to show upcoming 50 years in dropdown, you can set maxdate like,
this.maxDate = { year: this.now.getFullYear() + 50, month: 1, day: 1 };
In your component.html,
<input id="event" name="event" [(ngModel)]="model" (click)="event.toggle()" #event="ngbDatepicker" [min]="minDate" [max]="maxDate" ngbDatepicker>
Thanks to #kishoreaoe I got a way Forward.
I am Using Angular 6 and ng-Bootstrap .
I require to Set Min Date as today and Max-Date will be 1 year from today.
datecomponent.component.ts
import {NgbDateStruct} from '#ng-bootstrap/ng-bootstrap';
Min Date Logic
now: Date=new Date();
minDate :NgbDateStruct = { year: this.now.getFullYear(), month: this.now.getMonth() + 1, day: this.now.getDate() };
Max Date Logic
maxDate :NgbDateStruct={year: this.now.getFullYear()+1, month: this.now.getMonth()+1, day: this.now.getDate()}
datecomponent.component.html
<form class="form-inline">
<div class="form-group">
<div class="input-group">
<input class="form-control restricttextboxsize removeBorderright" placeholder="{{Initialdate | date:'dd/MM/yyyy'}}" name="dpStartDate"
[(ngModel)]="modelStartDate" ngbDatepicker #dStartDate="ngbDatepicker" [minDate]="minDate" [maxDate]="maxDate">
<div class="input-group-append dateborder">
<img src={{calendarImageinstance.standardimage}} class="pqestartdate grayscale" (click)="dStartDate.toggle()" />
</div>
</div>
</div>
</form>