fix(datetime): update active calendar display when value changes (#24244)

This commit is contained in:
Sean Perkins
2021-11-24 11:23:13 -05:00
committed by GitHub
parent 36a096c9b6
commit ec3bc52ff1
4 changed files with 138 additions and 19 deletions

View File

@ -93,6 +93,12 @@ export class Datetime implements ComponentInterface {
private minParts?: any;
private maxParts?: any;
/**
* Duplicate reference to `activeParts` that does not trigger a re-render of the component.
* Allows caching an instance of the `activeParts` in between render cycles.
*/
private activePartsClone!: DatetimeParts;
@State() showMonthAndYear = false;
@State() activeParts: DatetimeParts = {
@ -291,6 +297,25 @@ export class Datetime implements ComponentInterface {
*/
@Watch('value')
protected valueChanged() {
if (this.hasValue()) {
/**
* Clones the value of the `activeParts` to the private clone, to update
* the date display on the current render cycle without causing another render.
*
* This allows us to update the current value's date/time display without
* refocusing or shifting the user's display (leaves the user in place).
*/
const { month, day, year, hour, minute } = parseDate(this.value);
this.activePartsClone = {
...this.activeParts,
month,
day,
year,
hour,
minute
}
}
this.emitStyle();
this.ionChange.emit({
value: this.value
@ -911,7 +936,8 @@ export class Datetime implements ComponentInterface {
tzOffset,
ampm: hour >= 12 ? 'pm' : 'am'
}
this.activeParts = {
this.activePartsClone = this.activeParts = {
month,
day,
year,
@ -951,6 +977,10 @@ export class Datetime implements ComponentInterface {
this.ionBlur.emit();
}
private hasValue = () => {
return this.value != null && this.value !== '';
}
private nextMonth = () => {
const { calendarBodyRef } = this;
if (!calendarBodyRef) { return; }
@ -1135,7 +1165,7 @@ export class Datetime implements ComponentInterface {
{getDaysOfMonth(month, year, this.firstDayOfWeek % 7).map((dateObject, index) => {
const { day, dayOfWeek } = dateObject;
const referenceParts = { month, day, year };
const { isActive, isToday, ariaLabel, ariaSelected, disabled } = getCalendarDayState(this.locale, referenceParts, this.activeParts, this.todayParts, this.minParts, this.maxParts, this.parsedDayValues);
const { isActive, isToday, ariaLabel, ariaSelected, disabled } = getCalendarDayState(this.locale, referenceParts, this.activePartsClone, this.todayParts, this.minParts, this.maxParts, this.parsedDayValues);
return (
<button
@ -1213,21 +1243,22 @@ export class Datetime implements ComponentInterface {
ampmItems: PickerColumnItem[],
use24Hour: boolean
) {
const { color, workingParts } = this;
const { color, activePartsClone, workingParts } = this;
return (
<ion-picker-internal>
<ion-picker-column-internal
color={color}
value={workingParts.hour}
value={activePartsClone.hour}
items={hoursItems}
numericInput
onIonChange={(ev: CustomEvent) => {
this.setWorkingParts({
...this.workingParts,
...workingParts,
hour: ev.detail.value
});
this.setActiveParts({
...this.activeParts,
...activePartsClone,
hour: ev.detail.value
});
@ -1236,16 +1267,16 @@ export class Datetime implements ComponentInterface {
></ion-picker-column-internal>
<ion-picker-column-internal
color={color}
value={workingParts.minute}
value={activePartsClone.minute}
items={minutesItems}
numericInput
onIonChange={(ev: CustomEvent) => {
this.setWorkingParts({
...this.workingParts,
...workingParts,
minute: ev.detail.value
});
this.setActiveParts({
...this.activeParts,
...activePartsClone,
minute: ev.detail.value
});
@ -1254,19 +1285,19 @@ export class Datetime implements ComponentInterface {
></ion-picker-column-internal>
{ !use24Hour && <ion-picker-column-internal
color={color}
value={workingParts.ampm}
value={activePartsClone.ampm}
items={ampmItems}
onIonChange={(ev: CustomEvent) => {
const hour = calculateHourFromAMPM(this.workingParts, ev.detail.value);
const hour = calculateHourFromAMPM(workingParts, ev.detail.value);
this.setWorkingParts({
...this.workingParts,
...workingParts,
ampm: ev.detail.value,
hour
});
this.setActiveParts({
...this.workingParts,
...activePartsClone,
ampm: ev.detail.value,
hour
});
@ -1309,7 +1340,7 @@ export class Datetime implements ComponentInterface {
}
}}
>
{getFormattedTime(this.workingParts, use24Hour)}
{getFormattedTime(this.activePartsClone, use24Hour)}
</button>,
<ion-popover
alignment="center"