Skip to content

Resize handle on event it's disappearing #1753

Description

@ViktorDimitrievski

Hello mattlewis92,
Frist of all thank you for the angular-calendar library which is awesome work that you have done!

Describe the bug

After extensively using the Angular Calendar library, I encountered an issue that I believe might be a bug. However, it could also be an intended feature, and I couldn't find a definitive answer in the available examples or documentation.

To investigate further, I created an isolated project using the Angular Calendar library to reproduce the issue I faced in my main project.

Background:

  • The user can click on any segment to create an event.
  • Events can be resized
  • The calendar is set with specific hour limits ([dayStartHour]="9" [dayEndHour]="16").

Issue:
When a user resizes an event to the end limit of the day, the mwlResizeHandle disappears. This behavior makes it impossible to resize the event back to a shorter duration (e.g., reducing from 6 hours to 4 hours) by dragging from bottom to top, as the resize handle is no longer visible.

Supporting Information:

  • I have prepared two screenshots to illustrate the issue.
  • The code (TS and HTML files) used to reproduce this behavior is attached for your reference.

Please let me know if this is indeed a bug or expected behavior, and if there’s a workaround. Thank you for your time and assistance!

Minimal reproduction of the problem with instructions
ts file

import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ViewEncapsulation } from '@angular/core';
import {
	CalendarEvent,
	CalendarEventTimesChangedEvent,
	CalendarModule,
	CalendarView,
	CalendarWeekViewBeforeRenderEvent,
} from 'angular-calendar';
import { addHours, isBefore, isSameDay, setDay, setHours, setMinutes, startOfDay, subSeconds } from 'date-fns';
import { Subject } from 'rxjs';

export const colors: any = {
	red: {
		primary: '#ad2121',
		secondary: '#FAE3E3',
	},
	blue: {
		primary: '#1e90ff',
		secondary: '#D1E8FF',
	},
	yellow: {
		primary: '#e3bc08',
		secondary: '#FDF1BA',
	},
};

@Component({
	selector: 'app-preview',
	templateUrl: './preview.component.html',
	standalone: true,
	changeDetection: ChangeDetectionStrategy.OnPush,
	encapsulation: ViewEncapsulation.None,
	styles: [
		`
			.invalid-position .cal-event {
				background-color: #ad2121 !important;
				color: #fff;
			}

			.cal-disabled {
				background-color: #eee;
				pointer-events: none;
			}
		`,
	],
	imports: [CalendarModule],
})
export class PreviewComponent {
	dayStartHour = 9;
	dayEndHour = 16;
	todayDate = new Date();
	view: CalendarView = CalendarView.Week;

	viewDate = new Date();

	events: CalendarEvent[] = [
		{
			start: addHours(startOfDay(setDay(new Date(), 3)), 2),
			end: subSeconds(addHours(startOfDay(setDay(new Date(), 3)), 3), 1),
			title: 'An short event',
			color: colors.yellow,
			resizable: {
				beforeStart: true,
				afterEnd: true,
			},
			draggable: true,
		},
		{
			start: addHours(startOfDay(setDay(new Date(), 3)), 5),
			end: subSeconds(addHours(startOfDay(setDay(new Date(), 3)), 10), 1),
			title: 'A draggable and resizable event',
			color: colors.yellow,
			resizable: {
				beforeStart: true,
				afterEnd: true,
			},
			draggable: true,
		},
	];

	refresh = new Subject<void>();

	constructor(private cdr: ChangeDetectorRef) {}
	ngOnInit() {
		var event: CalendarEvent = {
			start: setHours(setMinutes(new Date(), 20), 16),
			end: setHours(setMinutes(new Date(), 40), 18),
			cssClass: 'invalid-position',
			title: 'After limit and red event',
			resizable: {
				beforeStart: false,
				afterEnd: false,
			},
			draggable: false,
		};
                 /**just for testing */
		setTimeout(() => {
			this.events = [...this.events, event];
			this.cdr.detectChanges();
		}, 5000);
	}

	validateEventTimesChanged = (
		{ event, newStart, newEnd, allDay }: CalendarEventTimesChangedEvent,
		addCssClass = true
	) => {
		if (event.allDay) {
			return true;
		}
		if (newEnd == undefined) {
			newEnd = setHours(newStart, 1);
		}
		delete event.cssClass;
		// don't allow dragging or resizing events to different days
		const sameDay = isSameDay(newStart, newEnd);

		if (!sameDay) {
			return false;
		}

		// don't allow dragging events to the same times as other events
		const overlappingEvent = this.events.find((otherEvent) => {
			return (
				otherEvent !== event &&
				!otherEvent.allDay &&
				((otherEvent.start < newStart && newStart < (otherEvent.end ?? new Date())) ||
					(otherEvent.start < newEnd && newStart < (otherEvent.end ?? new Date())))
			);
		});

		if (overlappingEvent) {
			if (addCssClass) {
				event.cssClass = 'invalid-position';
			} else {
				return false;
			}
		}

		return true;
	};

	eventTimesChanged(eventTimesChangedEvent: CalendarEventTimesChangedEvent): void {
		delete eventTimesChangedEvent.event.cssClass;
		if (this.validateEventTimesChanged(eventTimesChangedEvent, false)) {
			const { event, newStart, newEnd } = eventTimesChangedEvent;
			event.start = newStart;
			event.end = newEnd;
			this.refresh.next();
		}
	}

	beforeWeekViewRender(renderEvent: CalendarWeekViewBeforeRenderEvent) {
		renderEvent.hourColumns.forEach((hourColumn) => {
			const date = addHours(this.todayDate, 48);
			hourColumn.hours.forEach((hour) => {
				hour.segments.forEach((segment) => {
					delete segment.cssClass;
					debugger;
					if (isBefore(segment.date, date)) {
						segment.cssClass = 'cal-disabled';
					}
				});
			});
		});
	}
}

HTML file

  <mwl-calendar-week-view
    [viewDate]="viewDate"
    [events]="events"
    [refresh]="refresh"
    [dayStartHour]="dayStartHour"
	  [dayEndHour]="dayEndHour"
    (beforeViewRender)="beforeWeekViewRender($event)"
    [validateEventTimesChanged]="validateEventTimesChanged"
    (eventTimesChanged)="eventTimesChanged($event)"
  >
  </mwl-calendar-week-view>

Screenshots

before-limit
after=hitting-limit

Versions

  • package.json
  "dependencies": {
    "@angular/animations": "^18.2.0",
    "@angular/common": "^18.2.0",
    "@angular/compiler": "^18.2.0",
    "@angular/core": "^18.2.0",
    "@angular/forms": "^18.2.0",
    "@angular/platform-browser": "^18.2.0",
    "@angular/platform-browser-dynamic": "^18.2.0",
    "@angular/router": "^18.2.0",
    "angular-calendar": "^0.31.1",
    "date-fns": "^4.1.0",
    "rxjs": "~7.8.0",
    "tslib": "^2.3.0",
    "zone.js": "~0.14.10"
  },
  • Browser name and version:
    Chrome 131.0.6778.86 (Official Build) (64-bit)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions