Servoy-friendly Appointment-Task Calendar?

Good day, all,

I am currently looking for a good solution for an appointment calendar to use in my application. I’d like the user to be able to add their appointments, but I’d also like to be able to add appointments through code as a part of other functions. Other than that, I’d like pretty typical functions, ie, day, week, month views, etc. It also needs to work on both the smart client and web client.

I really like the Calendar Bean from IT2BE. It does everything I want to be able to do, but unfortunately, it does not operate on the web client.
I found a thread about an appointment calendar provided to the Servoy community by MindFire, mfModuleAppointments. It appears to work on both the web and smart client, but other than a mention of it a couple of years ago, I don’t see it mentioned anywhere else, or as an entry in ServoyForge.

I could “roll my own” using some HTML techniques, but I was wondering if others had found different solutions that work with Servoy.

Thanks for any advice you might have, and have a good day.

Ron

You can find the mindfire appointment module here: Whitepapers, Blogs, Infographics, Articles - Mindfire Solutions. I have saved the link for future reference, so I have no experience with the module whatsoever.

Hi Jos,

Thanks, I’ve done a download and am getting ready to play with it a bit.

Thanks.

Ron

we started this project: viewtopic.php?f=22&t=19124&p=102846&hilit=proof+of+concept#p102846

Hi Harjo,

Thanks for that information. Another set of great ideas! Has any more work been done on your project since this presentation?

As I said, Marcel has done a really nice job on the Calendar Bean, but the fact that is doesn’t run on the web client is a problem for me.

I’m going to take a look at the module that MindFire has provided and see if that will get me where I need to be.

Thanks again and have a good day.

Ron

Thought I’d throw another option in here as I’m working on something like this right now… though ours is more scoped for payroll data than appointments … UI is similar.

I learned this technique at ServoyWorld 2012 in a session with Patrick about Solution Model:

Done 100% with solution model… I’ve attached a sample (this is Patrick’s code from sw2012 he shared as a demo, so I think it’s probably OK to share here?)

there’s a LOT more utility code (getting the time / date from an x-y co-ordinate for example) in the sample (and our production implementation extends it a lot further) but the basic idea is :

Draw a new calendar with solution model :

function setupCalendar_week() {
	
//remove any old forms
elements.calendar.removeAllTabs();
	history.removeForm("calendar_week");
	solutionModel.removeForm("calendar_week");

//create a new solution model form
	var _jsForm = solutionModel.newForm("calendar_week", null, "calendar", false, 770, 1040);
	_jsForm.navigator = SM_DEFAULTS.NONE;

//add some variables to needed to render the calendar
	var _jsVariable = _jsForm.newVariable("_formWidth",JSVariable.INTEGER);
	_jsVariable.defaultValue = 780;
	
	_jsVariable = _jsForm.newVariable("_startDate",JSVariable.DATETIME);
	_jsVariable.defaultValue = _startDate;

//create a couple of solution model methods to track events 
	_jsForm.onResize = _jsForm.newMethod("function onResize(event) { forms.calendar_base.onResize_weekCalendar(event); }");
	
	_jsForm.newMethod("function onDoubleClick(event) { forms.calendar_base.onDoubleClick(event); }");

//start from a point on the screen...
	var _initialY = 35;
//draw the time labels
	for (var t = 1; t <= 24; t++) {
		var _lblTime = _jsForm.newLabel(utils.dateFormat(new Date(0,0,0,t-1,0,0),"HH:mm"), 10, _initialY + ((t-1)*40), 50, 40);
		_lblTime.name = "lbl_times_" + (t-1);
		if (t == 24) {
			_lblTime.styleClass = "times_bottom";
		} else {
			_lblTime.styleClass = "times";
		}
	}
//draw the calendar grid 
	var _initialX = 60;
	var _onActionGridCell = _jsForm.newMethod("function onAction_grid(event) { forms.calendar_base.onCellClicked(event); }");
	for (var d = 1; d <= 7; d++) {
		var _lblHeader = _jsForm.newLabel(utils.dateFormat(new Date(_startDate.getFullYear(),_startDate.getMonth(),_startDate.getDate() + (d-1),0,0,0),"EEE dd.MM."), _initialX + (100*(d-1)), _initialY - 20, 100, 20);
		_lblHeader.name = "lbl_header_day_" + d;
		_lblHeader.styleClass = "day_header";
		for (var dt = 1; dt <= 48; dt++) {
			var _lblGrid = _jsForm.newLabel("", _initialX + (100*(d-1)), _initialY + ((dt-1)*20), 100, 20);
			_lblGrid.name = "lbl_grid_" + d + "_" + (dt%2==0 ? (dt-2)/2 : (dt-1)/2) + "_" + (dt%2==0 ? 2 : 1);
			if (dt == 48) {
				_lblGrid.styleClass = "grid_absolute_bottom";
			} else if (dt%2==0) {
				_lblGrid.styleClass = "grid_bottom";
			} else {
				_lblGrid.styleClass = "grid_top";
			}
			
			if (d == 7) {
				_lblGrid.styleClass += "_right";
			}
			_lblGrid.onAction = _onActionGridCell;
			_lblGrid.showClick = false;
		}
	}
//enable resizing of elements
	setClientDesignHandles();
	if (!forms["calendar_week"].controller.getDesignMode()) {
		forms["calendar_week"].controller.setDesignMode(onDrag, onDrop, onSelected, onResize);
	}
	elements.calendar.addTab("calendar_week");
}

to add events :

//get the top left grid element for x-y references 
var _startElement = _jsForm.getComponent("lbl_grid_1_0_1");
	var _startX = _startElement.x;
	var _startY = _startElement.y;
	var _elementWidth = _startElement.width;
	var _dayOfWeek;
	var _columnsPerDay;
	for (i = 0; i < _eventsToAdd.length; i++) {
		var _event = _eventsToAdd[i];
		
		if (_dayOfWeek != _event.getDayOfWeek() || !_columnsPerDay) {
			_dayOfWeek = _event.getDayOfWeek();
			_columnsPerDay = getMaxColumnsPerDay(_dayOfWeek, _eventsToAdd);
		}
		
		var _x = _startX + _elementWidth * (_event.getDayOfWeek() - 1);
		var _height = Math.ceil((_event.end - _event.start) / 1000 / 60 * (20 / 30));
		var _y = _startY + _event.start.getHours() * 40 + _event.start.getMinutes() * (20 / 30);
		var _displayText = "<html><body>" + utils.dateFormat(_event.start,"HH:mm") + " - " + utils.dateFormat(_event.end,"HH:mm") + "
" + _event.subject + "</body></html>";
		var _eventWidth = (_elementWidth - _eventRightOffset) * (1 / (_event.overlappingEvents.length > 0 ? _columnsPerDay : 1));
		var _eventX = _x + (_columnsPerDay > 1 && _event.overlappingEvents.length > 0 ? (_event.overlapColumn - 1) * _eventWidth : 0);
		
		// create the element
		var _eventElement = _jsForm.newLabel(_displayText, _eventX, _y, _eventWidth, _height);
		_eventElement.name = "event_" + _event.uuid;
		_eventElement.background = _event.color;
		_eventElement.styleClass = "event";
		_eventElement.formIndex = 99999;
		_eventElement.borderType = _event.border;
		_eventElement.toolTipText = _event.getTooltip();
		_event.x = _eventX;
		_event.width = _eventWidth;
		
		// add event to _events array
		_events.push(_event);
	}

        //redraw the screen once the events are added 
	forms["calendar_week"].controller.recreateUI();

the sample data is again from SW2012 so you’ll probably have to click back to may 2012 before you see any data on screen!

calendar.servoy (23.1 KB)