Pausing AJAX requests

Currently, there is no ability to pause request.

Case:

  1. Listen for backend form submitting ajax request “onSave”
  2. Pause ajax request
  3. Get data from custom formWidget module, that returns Promise as data
  4. Wait until promise completed
  5. Push data to form
  6. Resume ajax request, let it collect data from form and send to backend

I tried listening for ajax:before-request but it doesn’t allow to pause request or cancel it.
ajax:request-start returns xhrRequest, but there is no option to pause it, only to duplicate cancel and create a new one with custom data.

There is should be more convenient event for this kind of tasks.

Hi,

Why not doing this way?

<form>
// your component::view1
// your component::view2
</form>

When the user is selecting some values in view1 ex: dropdown, you launch a request to update view2

At the end, you do your final request using the form.

—-

Just realized you’re talking about the backend. Do you need to show the data to the user?

If so, maybe creating a partial with inputs and dependsOn.

If not, just override onSave and merge your values in $_REQUEST

I’m making a formwidget that anyone can install from marketplace, so this is not an option.

Also, can’t do this, overriding controller handler from fromwidget seems like overkill to simple task. I just need to pause save request and resume it when Promise from formwidget is done.

Also, worth pointing out. Backend can have multiple formwidgets, we don’t know the name of the fields, so overriding onSave handler is not an option…

As I said, do the user needs to see the information returned (your “point 5.”)?

If not, why don’t you use data-request-success to execute what needs to be done in second place ?

Examine the documentation with a creative mindset; you may find a suitable solution for your needs.

The confirm-message event has a promise that works like you suggest:

$(window).on('ajax:confirm-message', function (event) {
    event.preventDefault();

    let promise = event.detail.promise;

    // this would be a modal which the user can submit in our real world scenario. 
    setTimeout(function () {
        $('#demo-field').val('some-value');

        promise.resolve();
    }, 5000);

    return true;
});

There is also an example in the documentation that resubmits the request on the same element:

addEventListener('app:stale-document', function (event) {
    if (confirm('Another user has updated this document, proceed?')) {
        oc.request(event.target, 'onUpdate', { data: {
            force: true
        }});
    }
});

Thanks for your suggestions, but they are wrong. Maybe I should clarify more what I’m trying to achieve.

I have a standard model form at the backend, with default field types, but only one or multiple has type “EditorJS”. The EditorJS is a WYSIWYG block-styled editor, and everything that is user doing with editor (typing, editing) is stored inside tab memory, but if you want to pull data out of EditorJS, you should call editorJs.save(). This method returns Promise that after completing gives you JSON data.

I want to put this JSON data inside the textarea of formwidget, and the trigger to start this process should be a standard onSave event that the user calls by clicking on “Save” button in the form.

So in my head it should work like this:

  1. Listen for ajax events on page
  2. If triggered event has onSave handler pause ajax event
  3. Trigger all fields with editorJs type and initate save promise and put result of promise inside textarea of each widget
  4. Resume ajax event, let it collect data inside form that already has editorjs data inside textarea.

This logic should work without user noticing anything, just slight longer standard saving process of model.

Can you propose how you would like this to work in code?

Could you listen for something like blur/onchange on EditorJs and call editorJs.save() at that point to do #3?

Your textarea could be populated before the default Save button is even pressed then.

That’s probably the route i’d go if it’s possible.

If you look at the dispatchChange() event on the editorjs docs - you can fire an event to let the editor know that a block has changed. You could then listen for this event and call the editorJs.save() method to populate the textarea whenever a block is changed.

So by the time you press the October save button your textarea will already contain it’s content.

1 Like

User can press CTRL+S/CMD+S hotkey which immediately call onSave method.

This solves the problem only if contents of EditorJS are small and doesn’t have any “heavy” blocks that should do some work on saving. That’s why EditorJS returns Promise but not directly content, because if the developer has blocks that do some heavy work on saving (we also should consider this) your method will not work. Calling a million times editorjs.save() method is not a solution of a problem in my opinion.

Sure. I’m not a “pro” in JavaScript, but something like this:

const editorjs = EditorJS(...);
const textarea = document.querySelector('form > textarea');

// Event that should fire before everything (gathering data, crafting request and etc.)
// Because we want to put data inside form that should be send in request
addEventListener('ajax:before-everything', event => {
    const { context } = event.details; // Get basic event information

    // We want to call this custom logic only on `onSave` event
    if (context.handler == 'onSave') {
        editorjs.save().then(outputData => {
            textarea.value = JSON.stringify(outputData);
            event.release(); // Resume the event
        }).catch(error => {
            alert(error.message);
            event.die(); // Kill the event if error occured
        });
    } else {
        event.release(); // Resume the event if wrong handler
    }
});