retejs / rete

JavaScript framework for visual programming
https://retejs.org
MIT License
9.86k stars 647 forks source link

Line is still connected when eliminating output #234

Closed juliandavidmr closed 5 years ago

juliandavidmr commented 5 years ago

When an output is added and then multiple connections are made, then I eliminate that output but the connections still exist

error mapper

Ni55aN commented 5 years ago

Show me your code :fox_face:

juliandavidmr commented 5 years ago

I have been following the error, it seems that the plugin "connection-plugin" does not work in certain cases. Failure occurs when "output" does not exist:

https://github.com/retejs/connection-plugin/blob/master/src/picker.js#L30

error connection

juliandavidmr commented 5 years ago

It eliminates the "Output" of a component and the "_output" of the plugin continues initialized, we must find a way to reset the value of "_output" (from connection-plugin) when an Output is removed from a component.

Ni55aN commented 5 years ago

I think that you forgot to remove connections before removing of Output (editor.removeConnection(connection))

juliandavidmr commented 5 years ago

I already did it, it works but there are residues of the connection, for example the sockets created with the directive, until now I think it may be the error.

juliandavidmr commented 5 years ago

I have tried in all ways, the connections are removed but the socket never work again.

    const originNode = this.getOriginNodes()[attribute.originAt];
    const output = originNode.outputs.get(Array.from(originNode.outputs.keys())[attribute.indexAttribute]);

    if (output.hasConnection()) {
      output.connections.map(c => {
        const attr = c.input.node.inputs.get(c.input.key);
        this.editor.view.removeConnection(c);

        attr.connections.map(c2 => {
          if (c2.output.key === output.key) {
            c2.remove();
          }
        });

        this.editor.removeConnection(c);
        c.remove();
      });

      /*const line = document.querySelector(
        `.connection, [class^=input-${ c.input.name.split(' ')[0] }], [class^=output-${ c.output.name.split(' ')[0] }]`
      );

      if (line) {
        line.remove();
      }*/
      // c.remove();
    }

originNode instance of Node

Ni55aN commented 5 years ago

this.editor.view.removeConnection(c); and c2.remove(); interferes to remove the connections correctly. Therefore this.editor.removeConnection(c); can no longer get connections to remove them, since they have already been removed from the list, but connection-render and other plugins have not know it.

editor.removeConnection will be enough

    input.connections.slice().map(editor.removeConnection.bind(editor));
    node.removeInput(input);

http://jsfiddle.net/Ni55aN/vmxdcLbq/91/

juliandavidmr commented 5 years ago

I have managed to reproduce the problem:

http://jsfiddle.net/anlijudavid/pxgms4jz/22/

error rete

Ni55aN commented 5 years ago

You are not calling editor.removeConnection to remove connection

Ni55aN commented 5 years ago

All operations to remove objects must be performed via editor

borja010 commented 5 years ago

Good evening,

I had the same error before and I tried a lot of ways without being able to fix it.

I was able to resolve the issue by cloning the node and re-doing the connections:

const {name, data, meta, position: [x, y]} = modified_node;
        const component = this.editor.components.get(name);
        let newNode = await component.createNode(data);
        newNode.meta = meta;
        newNode.position[0] = x;
        newNode.position[1] = y;
        this.editor.addNode(newNode);
        let input_modified = modified_node.inputs.get("entrada");
        let input_new = newNode.inputs.get("entrada");
        for(let i = 0; i<input_modified.connections.length; i++){
            let out = input_modified.connections[0].output;
            this.editor.removeConnection(input_modified.connections[0]);
            this.editor.connect(out, input_new);
        }
        for (let iterator = modified_node.outputs.values(), r; !(r = iterator.next()).done; ) {
            if(newNode.data.outputs.includes(r.value.name)){
                let output_new = newNode.outputs.get(r.value.key);
                for(let i = 0; i<r.value.connections.length; i++){
                    this.editor.connect(output_new, r.value.connections[i].input);
                }
            }
        }
        this.editor.removeNode(modified_node);

This is what I did.

juliandavidmr commented 5 years ago

Hello @borja010, I have also tried a lot of ways and I have not been able to solve it, I also thought of a solution like yours but I thought it was an extreme case, but after not knowing what happens I will follow your advice, thank you very much.

Sent from my Moto G(4) using FastHub

Ni55aN commented 5 years ago

@juliandavidmr you need to update the node and connections after node.removeOutput(output);

  // node.update(); //for vue render
  node._alight.scan()
  editor.view.updateConnections({node})
Ni55aN commented 5 years ago

@borja010 this should work

   input.connections.slice().map(editor.removeConnection.bind(editor));
   node.removeInput(input);

    node.update();
    editor.view.updateConnections({node})
borja010 commented 5 years ago

Let me try and I will let you know. Thank you for the follow-up :)

juliandavidmr commented 5 years ago

I have applied the connections and node update changes, but the editor completely fails, see the gif below:

86c5cfcc-596d-4e5a-804a-b30ef90b52d2

Ni55aN commented 5 years ago

I can not make a pause in the gif :)

borja010 commented 5 years ago

When I was debugging the same issue. I identify that the issue only happens with the output that is below from the one that is deleted and when you click the output, the picker detects the information from the output that was deleted.

juliandavidmr commented 5 years ago

That's right, the problem is that the socket of the eliminated Output continues to exist, on the other hand the connections plugin continues with the problem that I describe:

It eliminates the "Output" of a component and the "_output" of the plugin continues initialized, we must find a way to reset the value of "_output" (from connection-plugin) when an Output is removed from a component.

Ni55aN commented 5 years ago

I have changed render plugin and reproduced issue http://jsfiddle.net/Ni55aN/vmxdcLbq/102/

juliandavidmr commented 5 years ago

I just saw the example, it seems that this is the same problem

Ni55aN commented 5 years ago

This issue was fixed in vue-render-plugin v0.2.6. The problem was that it recreated the HTMLElement in the loop with a sockets, so the old one was lost

input.connections.slice().map(editor.removeConnection.bind(editor));
node.removeInput(input);

await node.update(); // await is a little hack that allows to execute the next command on next frame (insteadof Vue.nextTick)
editor.view.updateConnections({node})

http://jsfiddle.net/Ni55aN/vmxdcLbq/104/

juliandavidmr commented 5 years ago

Now it worked, thank you very much @Ni55aN . You have saved my life.