jerosoler / Drawflow

Simple flow library 🖥️🖱️
https://jerosoler.github.io/Drawflow/
MIT License
4.78k stars 741 forks source link

Weird connections behaviour when using async functions #308

Closed mcesaro closed 2 years ago

mcesaro commented 2 years ago

Hi @jerosoler , thank you again for your great tool. I'm using Drawflow for an application that allows the storage of flows on a server with standard REST API. In my initial version, I ask the name of the flow to load using the Window.prompt() method and I use the returned name to fetch the document from server, then load the flow like this:

//
// this is part of the downloadApp() function
//
// data is the raw response from server
var df = JSON.parse(data);
editor.clear();
editor.drawflow = df;
editor.load();

and all works well. Replacing Window.prompt() with SWAL (Sweet Alert2) requires the use of an async function:

async function altPrompt(label) {
var retval = await (async () => {
  const { value: appId } = await Swal.fire({
      input: 'text',
      inputLabel: label,
      inputPlaceholder: 'flow name',
      inputAttributes: {
          'aria-label': 'Flow Name'
      },
      showCancelButton: true
  })
  if (appId != null && appId.length > 0) {
    return appId;
  } else {
    return null;
  }
  })() 
  return retval;
}

If I fetch the flow from the server in this way:

async function fetchApp() {
  // const applId = window.prompt('Application ID:'); <- this works well!
  const applId = await altPrompt('Application ID:');
  await downloadApp(applId);
}

Then the flow loads correctly but the connections aren't. Connections appear as horizontal lines on top of the flow. I tried to call a refresh connection function like this:

function refreshConnections() {
  var df = editor.drawflow;
  var modules = df.drawflow;
  for (var module in modules) {
    var nodes = modules[module].data; // this is the array of node objects
    for (var node in nodes) {
      var dta = nodes[node];
      var key = dta.id;
      editor.updateConnectionNodes ('node-'+key)
    }
  }
}

but this only works if it's invoked after some timeout, like this:

async function fetchApp() {
  // const applId = window.prompt('Application ID:');  <- this works well!
  const applId = await altPrompt('Application ID:');
  await downloadApp(applId)
  setTimeout(() => {         // meh
     refreshConnections();
   }, 100);
}

This clumsy workaround works most of times. Not always, though. Note that using Window.prompt() the connections are always good. Note also that manually forcing a redraw, like changing current module, also draws the connections correctly, without the need of the editor.updateConnectionNodes() method.

I'm probably doing something wrong because I'm still learning Javascript, but I can't see what. Can you point me in the right direction?

Thanks Massimo

jerosoler commented 2 years ago

Why don't you use the editor.import method?

Try raising the settimeout to a higher time. 250-500 ...

mcesaro commented 2 years ago

Hi Jero, I replaced editor.load() with editor.import(df) but the result is the same, i.e. connections aren't displayed correctly. A higher timeout works better, however it creates a noticeable delay/flicker. Still I'm wondering why with the blocking prompt this won't happen... Thank you for you support.

jerosoler commented 2 years ago

It may be that the prompt is modifying some css. It's the only thing I can think of. If you want to prepare a codepen or a codesandbox and we will look at it.

mcesaro commented 2 years ago

I was able to determine that the problem lies in an interaction with https://sweetalert2.github.io/ I replaced this library with an equivalent for modal dialog (nor using the async functions like SWAL2), and the problem disappears.

jerosoler commented 2 years ago

Oh excellent!