Premium support for our pure JavaScript UI components


Post by rclarke »

Hi,

We’ve extended the ProjectModel and overridden the sendRequest function to implement our own transport, but we’re getting “Error: Interleaved load operation detected” from the success callback. In onCrudRequestSuccess, request is set to a value from activeRequests, but it’s not clear where this should be set - the sendRequest function in AjaxTransport doesn’t seem to set it anywhere.

Here's a simple version of our project model class just to figure out how to use it:

class GanttProjectModel extends JsonEncoder(AbstractCrudManagerMixin(ProjectModel)) {
	sendRequest(request) {
		console.log(request);

	let response = '';
	return request.success.call(request.thisObj || this, response, null, request);
}
}

A couple of questions:

  • How are we supposed to do this so that request is set correctly in the callback?

  • The AjaxTransport and JsonEncoder are mixed into the ProjectModel, so to completely swap one of these out, we’d need to reimplement the entire ProjectModel? Is there any way around this?


Post by Maxim Gorkovsky »

Hello.
This is the first time I hear about this exception. I've found a related comment:

// This situation should never occur.
// In the load() method, if a load is called while there is a load
// ongoing, the ongoing Transport request is cancelled and loadCanceled triggered.
// But having got here, it's too late to cancel a Transport request, so
// the operation is unregistered below.
// In the sync() method, if a sync is called while there is a sync
// ongoing, it waits until completion, before syncing.
// The activeRequest for any operation should NEVER be able to be
// replaced while this operation is ongoing, so this must be fatal.
if (request?.id !== requestId) {
    throw new Error(`Interleaved ${requestType} operation detected`);
}

Probably you forgot to put a request id in your override? Your syncRequest override should do smth like this:

async sendRequest(request) {
    // Need to move these actions to next microtask to give crud manager some time to store the request id
    await Promise.resolve();

    const { type, data, success } = request;

    // Emulate JSON response from the server. It doesn't have data yet, we will add it later
    const response = { success: true, type, requestId: data.requestId }; // <- notice requestId here

    // Emulate Response instance, Project will try to read text property
    const responseRaw = { text: async () => response };
    // Prepare response data for Project here
    const responseData = { tasks : { rows : [...], removed : [...] }, ... }
    Object.assign(response, { ...responseData });
    success?.call(request.thisObj || this, responseRaw, {}, request);
}

The AjaxTransport and JsonEncoder are mixed into the ProjectModel, so to completely swap one of these out, we’d need to reimplement the entire ProjectModel? Is there any way around this?

You can extend the project model like this:

const MyEncoder = Target => class MyEncoder extends Target {
  // JsonEncoder will covert data to JSON leaving data set empty of any instances. However,
  // if you're saving task, it may send an array of baselines which contain record instances.
  // Those record instances should either be cleared or converted to regular objects to
  // avoid infinite loop on response apply
  encode(data) { return data; }
  decode(data) { return data; }
}

const MyLocalTransport = Target => class MyLocalTransport extends Target {
  async sendRequest() {...}
}

export default class MyProjectModel extends MyLocalTransport(MyEncoder(ProjectModel)) {
    static get defaultConfig() {
        return {
            autoSync: true,
            transport: {
                load: { url: "load" },
                sync: { url: "sync" }
            }
        };
    }
}

// ProjectModelClass is not customizable, so you will have to provide project instance to the gantt
const project = new MyProjectModel();
const gantt = new Gantt({ project });

Post by Maxim Gorkovsky »

We also have a ticket to improve CRUD API to make it simpler to extend, current version is not very user friendly: https://github.com/bryntum/support/issues/3598


Post by rclarke »

Thanks Maxim, I'll give that a try and get back to you. We're definitely interested in the issue you've linked, by the way!


Post Reply