retejs / rete

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

How to add custom component of react in controls and retrieve data from that component #454

Closed mobeen7asif closed 1 year ago

rete-js[bot] commented 1 year ago

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 10 days.

simonetassi commented 9 months ago

Did anybody find a solution for this?

Ni55aN commented 9 months ago

@simonetassi does this example help?

simonetassi commented 9 months ago

@Ni55aN yes, but I'm still stuck. I am trying to get the current value of a select custom component I made that I use as Control from the node that contains it. I'm able to update the value of the control everytime that the component is updated but I don't know how to retreive the updated value from the node itself. I hope my explanation is clear 😅.

here is my Control/Component:

import { Component, Input } from "@angular/core";
import { ClassicPreset } from "rete";

export class CustomDropDownControl extends ClassicPreset.Control {
  value?: string;

  constructor(public select: string[]) {
    super();
  }

  setValue(value?: string): void {
    this.value = value;
    console.log(this.value);
  }

  change?: (value: string) => void;  
}

@Component({
  selector: "app-custom-dropdown",
  templateUrl: './custom-dropdown.component.html',
  styleUrls: ['./custom-dropdown.component.css']
})
export class CustomDropDownComponent {
  @Input() data!: CustomDropDownControl;
  onChange(value: any){
    this.data.setValue(value.value);
  }
}

and here my Node:

import { ClassicPreset as Classic } from "rete";
import { CustomDropDownControl } from "src/app/custom-dropdown/custom-dropdown.component";

const socket = new Classic.Socket('socket');
export class ActionInputNode extends Classic.Node<
    { in: Classic.Socket },
    { value: Classic.Socket },
    { value: CustomDropDownControl }>
{
    width = 180;
    height = 120;
    thingId: string;
    name: string;
    val: string;
    constructor(action: [string, Object], thingId: string, change?: void) {
        super(action[0]);
        this.name = action[0];
        this.val = "";
        this.thingId = thingId;
        this.addInput('in', new Classic.Input(socket));
        this.addOutput('value', new Classic.Output(socket));
        const input = Object.entries(action[1]).find(pair => pair[0] == "input");
        const e: string[] = Object.values(input![1])[0] as string[];
        this.addControl('value', new CustomDropDownControl(e));
    }

    data(): { value: string } {
        return {
            value: this.controls.value.value || ""
        };
    }
}

Probably i'm doing something wrong but I don't know what it is...

Ni55aN commented 9 months ago

Every time you select an item in dropdown UI, CustomDropDownControl.setValue should be called. Does it work?

I don't know how to retreive the updated value from the node itself

this.controls.value.value should have the value provided by CustomDropDownComponent.onChange. But, you have it inside data(), which is probably a part of DataflowEngine. Do you call reset every time you want to get a new selected dropdown item? https://retejs.org/docs/guides/processing/dataflow#start-processing

simonetassi commented 9 months ago

@Ni55aN I know it's part of DataflowEngine, but i wasn't able to introduce it in my project so that part is not doing anything relevant. So what would you suggest me to keep the "val" variable updated? If i assign to it this.controls.value.value it will be set with a value and never updated again.

Ni55aN commented 9 months ago

to keep the "val" variable updated

use this.controls.value.value directly or through a getter

get val() {
  return this.controls.value.value;
}
simonetassi commented 9 months ago

@Ni55aN using the getter I get undefined, even if in the control the value is updated.

This is what I'm doing to retreive it:

function lastWasActionInput(node: BasicFunctionNode, connections: Conn[], nodes: Node[]) {
  const c = connections.find(conn => conn.target === node.id) || null;
  if ((c != null) && (getNodeById(nodes, c.source) instanceof ActionInputNode)) {
    const connectedNode = getNodeById(nodes, c.target) as ActionInputNode;
    console.log(connectedNode.val);
    return [true, connectedNode.val];
  } else {
    return [false, ''];
  }
}

EDIT: after reviewing my code I found a logic error in it. At row 4 of the provided code it should be:

const connectedNode = getNodeById(nodes, c.source) as ActionInputNode;

Everything works now perfectly! Thanks for your support and for developing this amazing library.