onEventCollision - onBeforeEventChanged fires anyway

Hi… if I’m using both onEventCollision and onBeforeEventChanged, I seem to get erratic behaviour.

When an event is moved and a collision is detected, I would expect the transaction to be reversed and the event returned to it’s previous place, end of story.

But I’m finding that even if a collision is detected, onBeforeEventChanged is being fired. (This contains logic to save the details back to the DB server).

How can I prevent this from firing if there’s been a collision detected?

thanks

Hello,
this is an expected behavior.
onBeforeEventChanged indicates that event has been drag-and-dropped and changes are about to be applied but still can be canceled. I.e. it should not notify the backend about modifications of a client-side data, since the trigger of this event does not guarantee that any changes will be applied.

Please use this event instead
docs.dhtmlx.com/scheduler/api__s … event.html

Thanks, but I don’t think this makes sense.

The client-side checks to see if there is a collision, and has an opportunity to return false. Then, before saving, I need to validate on the server side to see if there is any issue. So I need to use onBeforeEventChanged to check this so it can return false if necessary.

Or am I missing something?

That may lead to a different question)
How exactly do you do an ajax validation? Unless you use synchronous request, you’ll need to put some additional code for async validation.

To the original issue - onBeforeEventChanged indicates that the data item is about to be modified and provides an entry point for a custom validation.
The configuration where multiple validators applied (in this case - validation from the collision extension, and validation done by your code) should be expected, and the fact that client side performs a checking for a collision shouldn’t interfere with performing your custom checking.

I.e. onBeforeEventChanded triggers all validators which should check the action and return true/false to indicate whether the action should be canceled,
and if operation passes all validators then scheduler fires onEventChanged which triggers saving changes to the datasource.

If you’re going to use onBeforeEventChanged in order to save changes - it kind of goes in opposite to the designed action flow and a certain amount of struggling with the library should be expected.

If this still makes no sense, please clarify what happens in your code so I could better understand the issue.

Hi Aliaksandr

Yes I’m doing a synchronous ajax request, as follows:

		scheduler.attachEvent("onBeforeEventChanged", function (ev, e, is_new, original){
			var error = false;
			if (!is_new) {
				if(confirm('Are you sure you wish to move this meeting?')) {
					var URL = "sched.moveappt.asp" +  
								"?id=" + ev.id + 
								"&start=" + ev.start_date.toString("yyyy-MM-dd+hh:mm:ss") + 
								"&end=" + ev.end_date.toString("yyyy-MM-dd+hh:mm:ss") + 
								"&locationid=" + ev.room_id;
					$.ajax({url: URL, 
						statusCode: {
							409: function() {
								alert("This meeting conflicts with another!");
								error = true;
							}
							401: function() {
								alert("You are not allowed to do this");
								error = true;
							}
							500: function() {
								alert("Internal Error");
								error = true;
							}
						}
					});
				} else {
					error = true;
				}
				
				if (error == true) {
					return false;
				}
			}

			return true;
		});		

It is generally good practice to validate on both client and server side. I don’t mind if the actual save takes place later in onEventChanged, but this still doesn’t avoid the above issue - that there is no point performing a server validation if client side already fails - and I don’t want to inform the user twice of a validation issue.

Is this clearer?
thanks

Hello.

If you are using synchronous request to check collision you could just return true in event handler to prevent event moving.
In common case server side checking performs before saving event on the server side. Saving request sends from onEventChanged handler. docs.dhtmlx.com/scheduler/api__s … event.html
This event will not be fired if collision on client side was found. Server side should check collisions before exact inserting to DB and should return error if there is collision.

But onEventChanged does not have the ability to reject or roll back the change in the scheduler. So it is too late to perform server-side checking. So how can that be the recommended place to do it?

Surely it is important to check server-side before the change is committed?

In any case, I still don’t understand why, if a collision is detected, the other events (onBeforeEventChanged) should even be fired… as the change was already rejected by the collision detection. In what circumstances would you then still want the option to change the event if it has been rejected?

Hi,
thanks for the details. I think I understand the issue better now, there are two main points
1)

that there is no point performing a server validation if client side already fails

I don’t want to inform the user twice of a validation issue.

  1. Currently the event handlers may be called in arbitrary order (they in fact are called in the same order they are attached, but this due to implementation and not a design decision), based on aggregated return value the action is either passed to next stage or is canceled.
    Some redundancy is expected although does not seem to be a big issue.

  2. This seems like an API issue. There is no public event that would inform you that action has not passed the validation (i.e. one or several onBeforeEventChanged returned false).
    you can detect when action has passed validation from firing of onEventChanged, but there is no event that would indicate that the change has been discarded. We will check for a solution.
    Right now I can suggest some code workaround for showing a single error message when one or many onBeforeEventChanges discards the operation

Also, you can do an additional checking on a backend during the save operation handler This would also make sense since things could have changed between client validation has been performed and when http request for data saving receives the handler. Especially since such request can be sent manually either from browser console or some external tool, so generally you’ll want to validate the request data right before you write it into the db.

In that case you can return an ‘invalid’ status of an action and then reload calendar events from the server in order to re-sync the data.
docs.dhtmlx.com/connector__php__ … ationerror
docs.dhtmlx.com/scheduler/api__s … _load.html

This is why it makes much more sense to me that the server update happens in onBeforeEventChanged. Then the server has a chance to reject the change, but if it doesn’t it is saved immediately, and the front-end can then revert to the old values or update to the new values as necessary.

With your current logic, you are telling me I have to check with the back end twice.

Hi all,

I am using a the dhtmlxScheduler_v4.3.35_commercial version of this plugin on a PHP project. I also need the collision plugin.

I recently found a very annoying bug in the collision plugin, probably related with the objects passed from onEventCollision to onBeforeEventChanged event.

Basically:

To reproduce:
Create an event
Drag it onto another one, it will bring the event back to the original position.
Now, try to drag it again, it will disappear!

What is happening?
The Event object passed by the onBeforeEventChanged event has an “Invalid Date” Date object type as end_date attribute.

scheduler.attachEvent("onBeforeEventChanged", function(ev, e, is_new, original){
    // When dragging the second time, ev.end_date contains "Invalid Date" Date object
    return true;
});

Possible temporary fix (porkaround)
Control: if the end_date attribute is invalid, then populate it with the original one.

scheduler.attachEvent("onBeforeEventChanged", function(ev, e, is_new, original){
    if (is_new===false){
        if ( Object.prototype.toString.call(ev.end_date) === "[object Date]" && isNaN(ev.end_date.getTime()) ) { 
            ev.end_date=original.end_date;
        }
    }
return true;
});

This solution kinda works, but it still behaves quite weirdly because the event is still binded with the mouse pointer so, when the Event rectangle will appear again, it will have probably lost the start_date information.

It happens only if you drag the whole Event rectangle. Probably there is a missing control in the collision plugin on the end_date when dragging the whole Event rectangle. Please, can you properly fix it?

Hello,

  1. The collision extension shouldn’t cause the problem. Perhaps the issue is related to cancel of onBeforeEventChanges event.
    To check it you can try disable the collision extension and always cancel changes:
scheduler.attachEvent("onBeforeEventChanged", function() { return false; });

If the issue still occurs, the reason is another.

  1. Please, check your code if you have onEventColiision or drag and drop events handlers. Also disable them and check if the issue occurs.

  2. If points above don’t help you find the cause of the problem, please provide with the demo where we can reproduce the issue or provide with access to the application. We were not able to reconstructed locally.