When multiple tasks are dragged together, I want them to only call the batch update request once, instead of calling the single task modification request one by one

When multiple tasks are dragged together, I want them to only call the batch update request once, instead of calling the single task modification request one by one.
if there is a batchUpdate or if tasks are updated does the dataProcessor provide any functionality to send all data in same request in those particular scenario?

Hello,
Unfortunately, there is no built-in solution at the moment. However, you can achieve this functionality manually.

For example I use the following date processor:

const server =   "/data";
gantt.load(server);

const dp = gantt.createDataProcessor((entity, action, data, id) => { 
	switch(action) {
		case 'create':
			return gantt.ajax.post(
				server + '/' + entity,
				data
			);
		break;
		case 'update':
			return gantt.ajax.put(
				server + '/' + entity + '/' + id,
				data
			);
		break;
		case 'delete':
			return gantt.ajax.del(
				server + '/' + entity + '/' + id
			);
		break;
	}
});

To prevent sending requests for each task, you can utilize the onBeforeUpdate event:

let sendData = false;

dp.attachEvent('onBeforeUpdate', (id, state, data) => {
	if (data.start_date && state == 'updated' && !sendData) {
		return false;
	}

	return true;
});

Next you need to add task.$dataprocessor_class = "gantt_updated"; property for updated tasks:

gantt.attachEvent('onAfterTaskUpdate', (id,task) => {
	task.$dataprocessor_class = 'gantt_updated';
});

After the drag and drop is complete, you can send all the updated tasks to the server. It can be done with the help of the onAfterTaskDrag event. However, since the onAfterTaskDrag event is called for each task, it is necessary to track the moment when the event will be fired for all selected tasks and only then send the changes to the server. To accomplish this, you can add all selected tasks id to the set (for example, selectedTasksSet) and then compare it with the set of moved tasks:

let selectedTasksSet = new Set();
let movedTasksSet = new Set();

gantt.attachEvent("onTaskMultiSelect", (id, state, e) => {
	if (state === true) {
		selectedTasksSet.add(id);
	} else {
		selectedTasksSet.delete(id);
	}
});

gantt.attachEvent('onAfterTaskDrag', (id, mode, e) => {
	if (!movedTasksSet.has(String(id))){
		movedTasksSet.add(String(id));
		
		if (
			movedTasksSet.size === selectedTasksSet.size &&
			[...movedTasksSet].every(taskId => selectedTasksSet.has(taskId))
		) {
			sendChanges();
		}
		setTimeout(() => {
			movedTasksSet.clear();
		}, 0)
	}
});

function sendChanges() {
	sendData = [];

	gantt.eachTask((task) => {
		if (task.$dataprocessor_class) {
			const taskClone = gantt.copy(task);
			taskClone.start_date = gantt.date.date_to_str(gantt.config.date_format)(taskClone.start_date);
			taskClone.end_date = gantt.date.date_to_str(gantt.config.date_format)(taskClone.end_date);
			sendData.push(taskClone);
		}    
	});

	console.log('sendData', sendData);
	
	gantt.ajax.post({
		url: server, 
		data: {
			data: sendData
		}
	}).then((response) => {
		// if (response.status == 200) {
			gantt.eachTask((task) => {
				if (task.$dataprocessor_class) {
					task.$dataprocessor_class = null;
				}
			})

			gantt.render();
		// }
	});
	
	sendData = false;
}

Here is an example: DHTMLX Snippet Tool
Please note that this is not a complete example and does not cover all possible cases of changing tasks. You may need to expand the code accordingly.