We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date
close icon

Rebind data

Hello,
I am currently working on rebinding data for ejs-diagram component. I didn't find anything in your docs, so I decided to rebind data same way as they are bind - using method updateDiagram. This caused problem. If user moves node, diagram remembers wrong position, so user can't click on element. I have debuged event in syncfussion library and found out, in method findObjects(region) { let quads = this.findQuads(region); ..... findQuads returns wrong offsets for object moved by user. 
However, when my method updateDiagramIsCalled is called again, ejs-diagram will refresh its internal data and node is once again clickable. But after user moves node problem will happen again.

Code that binds elements is pasted bellow.

  private updateDiagram() {
    const bindNodeModel = (callback: (diagramDiagram=> void=> (
      nodeModelNodeModel,
      elementElementModel,
      diagramDiagram
    ) => {
      nodeModel.id = `node_${element.Id}`;
      nodeModel.offsetX = element.PosX;
      nodeModel.offsetY = element.PosY;
      nodeModel.width = element.Width;
      nodeModel.height = element.Height;

      const elementType = getElementModelType(element);
      switch (elementType) {
        case ModelType.InputModel:
          nodeModel.shape = { type: 'Basic'shape: 'Ellipse' };
          nodeModel.style = {
            strokeColor: '#87cc86',
            fill: '#87cc86',
          };
          nodeModel.annotations = [
            {
              content: element.Name,
              style: { color: 'black' },
            },
          ];

          nodeModel.ports = [
            {
              offset: { x: 1y: 0.5 },
              visibility: PortVisibility.Visible,
              shape: 'Circle',
              constraints: PortConstraints.OutConnect,
              id: `node_${element.Id}-out-0`,
            },
          ];

          nodeModel.constraints =
            // tslint:disable-next-line: no-bitwise
            ~NodeConstraints.OutConnect & ~NodeConstraints.InConnect;
          break;
        case ModelType.OperationModel:
          nodeModel.shape = { type: 'Flow'shape: 'Terminator' };
          nodeModel.style = {
            strokeColor: '#0bafd2',
            fill: '#0bafd2',
          };
          nodeModel.annotations = [
            {
              style: { color: 'black' },
            },
          ];
          nodeModel.ports = [
            {
              offset: { x: 0y: 0.3 },
              visibility: PortVisibility.Visible,
              shape: 'Circle',
              constraints: PortConstraints.InConnect,
              id: `node_${element.Id}-in-0`,
            },
            {
              offset: { x: 0y: 0.7 },
              visibility: PortVisibility.Visible,
              shape: 'Circle',
              constraints: PortConstraints.InConnect,
              id: `node_${element.Id}-in-1`,
            },
            {
              offset: { x: 1y: 0.5 },
              visibility: PortVisibility.Visible,
              shape: 'Circle',
              constraints: PortConstraints.OutConnect,
              id: `node_${element.Id}-out-0`,
            },
          ];
          nodeModel.constraints =
            // tslint:disable-next-line: no-bitwise
            ~NodeConstraints.OutConnect & ~NodeConstraints.InConnect;
          break;
        default:
          nodeModel.style = {
            fill: '#ffeec7',
            strokeColor: '#f5d897',
            strokeWidth: 1,
          };
          nodeModel.annotations = [
            {
              content: element.Name,
              style: { color: 'black' },
            },
          ];

          nodeModel.ports = [
            {
              offset: { x: 0y: 0.5 },
              visibility: PortVisibility.Visible,
              shape: 'Circle',
              constraints: PortConstraints.InConnect,
              id: `node_${element.Id}-in-0`,
            },
          ];
          nodeModel.constraints =
            // tslint:disable-next-line: no-bitwise
            ~NodeConstraints.OutConnect & ~NodeConstraints.InConnect;
          break;
      }

      callback(diagram);
    };

    const bindingCallback = (diagramDiagram=> {
      diagram.bringToCenter(new Rect(400100100100));
    };

    this.diagramData = {
      id: 'Id',
      dataSource: new DataManager(this.templateModel.Elements.ElementModel),
      doBinding: bindNodeModel(bindingCallback),
    };

    this.connectors = getConnectors(this.templateModel);
    this.onDiagramModeChange(this.mode);
  }


8 Replies

SG Shyam G Syncfusion Team September 13, 2019 12:17 PM UTC

Hi Gabo, 

Could you please confirm us whether you need to update diagram node properties dynamically or need to update datasource properties of layout dynamically? . Could you please explain your exact requirement which you need to perform with nodes? So, we can provide a solution based on it. 

Regards, 
Shyam G 



GE Gabo EE September 13, 2019 02:18 PM UTC

Hello Shyam,
I will describe you basic flow of application I am trying to build.

1. Application gets json model from Web API. This json model is my domain description, that we are trying to render with ejs diagram.
2. json data are used as dataSource for diagramData - @Input [dataSourceSettings] of ejs. Binding is done in method updateDiagram - code below
    this.diagramData = {
      id: 'Id',
      dataSource: new DataManager(this.templateModel.Elements.ElementModel),
      doBinding: bindNodeModel(bindingCallback),
    };
3. ejs diagram invokes doBinding and our domain model is mapped to nodeModel 
4. Diagram is rendered for first time
5. User drags new node from ejs symbol pallate to ejs diagram.
6. Event (collectionChange) is triggered. At this moment application needs to know, that user added new node to enhance new node with our business logic properties - default annotation, ports, etc. Application saves new node to this.templateModel.Elements.ElementModel
7. We need to propage changes to ejs now, to show enhanced node. this.templateModel.Elements.ElementModel is changed and updateDiagram() is called again. This is where I would image syncfussion has some kind of rebind() method on diagram object or datasouce/dataManager object, I could call with new array of objects. Syncfussion should compare new array with new one and rerender changed elements internally
8. User changes some of properties via Element detail - outside of ejs diagram. This change needs to be shown on ejs diagram. this.templateModel.Elements.ElementModel is changed and updateDiagram() is called again.
9. User drags nodes around the ejs diagram. Event is send from ejs diagram and we are updating diagram.this.templateModel.Elements.ElementModel, but not calling updateDiagram() - we don't need to show any new change.
10. This is the point where begins problem with clickable node - i wrote about it in the last post - old data in let quads = this.findQuads(region)
11. User change some property in Element detail. this.templateModel.Elements.ElementModel is updated and updateDiagram() is called
12. updateDiagram() fixes problem with nonclickable node - node is clickable again
13. User click save button and this.templateModel.Elements.ElementModel is send to Web API 

Please inform me, if you do understand the concept.

Is this flow posible using syncfussion?
Is there any method that I can use to rebind new data send to ejs diagram (as I mentioned in step 7) without causing problems in step 10.

I am attaching screenshot of application to better understand concept.

Thank you for your response.


Attachment: screenshot_97e2b189.zip


SG Shyam G Syncfusion Team September 16, 2019 05:52 AM UTC

Hi Gabo, 

Yes, we can add new node to the dataSource collection at runtime. Please refer to a code example in which we have shown how to add new node to dataSource at runtime. We added two nodes to the dataSource set at runtime in our sample. Similarly, in the dataSource collection, you can add nodes that are taken from the palette to the diagram. Please ensure that when pushing node to the dataSource property at runtime, an Id and parentId property are right. 

Code example: 

public addDataSource() { 
      //add new node to datasource 
            this.diagram.dataSourceSettings.dataManager.dataSource.json.push( { 'Name': 'Consulting', 'Category': 'Business' }, { 'Name': 'HR', 'Category': 'Business' }); 
            this.diagram.clear(); 
            //refresh the diagram 
            this.diagram.refresh(); 
   



Please let us know if any concerns. 

Regards, 
Shyam G 



GE Gabo EE September 16, 2019 07:48 AM UTC

Would history work if I call?

//refresh the diagram 
this.diagram.refresh(); 

User adds new element by dragging node from symboll-pallete - this triggers few events from ejs diagram, what is the best event to listen to? What is the event, on which I want to call refresh?  I tried your code and I got errors, because event which was triggered by dropping element did not finish before calling refresh. I tried listening on (drop), collection changing event (10), collection changed event (14).






SG Shyam G Syncfusion Team September 17, 2019 02:58 PM UTC

Hi Gabo, 

Query 
Response 
Would history work if I call? 
 
//refresh the diagram  
this.diagram.refresh();  

The history will be cleared once the diagram is refreshed. 
User adds new element by dragging node from symboll-pallete - this triggers few events from ejs diagram, what is the best event to listen to? What is the event, on which I want to call refresh?  I tried your code and I got errors, because event which was triggered by dropping element did not finish before calling refresh. I tried listening on (drop), collection changing event (10), collection changed event (14).  
  • We should enable AllowDrop Constraints which shows highlighter when we drag node from palette and hover on the node in diagram.
  • You can drop the node once the highlighter has been displayed. When you drop a node on the another node, the drop event is initiated.
  • In this event, you can add new connector and establish a connection between the node dropped. Refer to the instance code below and the sample below.
 
Code example: 
 
    //Defines the default node properties 
    public nodeDefaults(obj: NodeModel): NodeModel { 
       
        //AllowDrop Constraints  
        obj.constraints = NodeConstraints.Default | NodeConstraints.AllowDrop;   
  
        return obj; 
    }; 
 
//drop event 
  public onDrop(args: any): void {   
   setTimeout(()=>{    
    let connector: ConnectorModel={}; 
    if (args.element && args.target) { 
      if (args.element) { 
        //get an connector object  
         connector = this.diagram.getObject(args.element.inEdges[0]); 
      } 
      // this block executed when we drag any node in diagram and drop it onto the another node 
      if (connector) { 
        //update connector source and target id  
        connector.sourceID = args.target.id; 
        connector.targetID = args.element.id; 
        this.diagram.dataBind(); 
      } else { 
        // this block executed when we drag  node in palette and drop it onto the node in diagram 
        this.diagram.add({id: 'connector' + randomId(), sourceID: args.target.id, targetID: args.element.id});    
        this.removeElementsByClass('e-diagram-highlighter')  
      }  
      //To update an layout  
      this.diagram.doLayout(); 
    } 
    }, 100);  
  } 
 
 
 


The node highlighter is not removed once we drop a node onto the another node in diagram. We have logged a defect report. The patch for this issue will be available on 8th October, 2019. You can track the status of the bug in the below feedback link. 


We have provided a workaround in the above sample to remove the highlighter. 


Regards, 
Shyam G 



SG Shyam G Syncfusion Team October 8, 2019 08:40 AM UTC

Hi Gabo, 

We have fixed the reported issue and included in our volume 3 release. Please download it from below link. 


Regards, 
Shyam G 



DT Durgesh Tirumala March 16, 2020 11:39 AM UTC

Hi Gabo,

Kindly help me with the code. I have been working sample of thing.

Regards,
Durgesh


SG Shyam G Syncfusion Team March 17, 2020 05:38 AM UTC

Hi Durgesh, 

We have created a sample in which you can add a new node into the layout by dragging the node from the palette and drop it onto the node in the diagram. You can find the code example from our earlier update. Please find the sample below with latest version. 


Regards, 
Shyam G 


Loader.
Live Chat Icon For mobile
Up arrow icon