Tagged Custom Vaadin Component is not added to the MainView layout

Viewed 45

I'm trying to add my custom vis component to MainView VerticalLayout. But it is rendered above the layout and the layout itself contains an empty component tag.

Custom component code

Here I'm tagging my component as "div"

@JsModule("./visjs-test.js")
@NpmPackage(value = "vis", version = "0.110.0")
@Tag("div")
public class VisJs extends Component {

    public VisJs(List<VisJsEdge> edges, List<VisJsNode> nodes) throws JsonProcessingException {
        ObjectWriter owForEdges = new ObjectMapper().writer().withDefaultPrettyPrinter();
        ObjectWriter owForNodes = new ObjectMapper().writer().withDefaultPrettyPrinter();

        String jsonEdges = owForEdges.writeValueAsString(edges);
        String jsonNodes = owForNodes.writeValueAsString(nodes);

        getElement().executeJs("window.initThree($0, $1, $2)", this, jsonEdges, jsonNodes);
    }
}

visjs-test.js:

Here I'm filling nodes and edge of future network and trying to render it

import {DataSet, Network} from "vis";

class VisJsTest {
    init(element, edges, nodes) {
        this.element = element;

        var loadedNodes = JSON.parse(nodes);
        
        var _this = this;
        var step;
        for (step = 0; step < loadedNodes.length; step++) {
            loadedNodes[step] = this.fillNode(loadedNodes[step]);
        }
        this.nodes = new DataSet(loadedNodes);
        
        var loadedEdges = JSON.parse(edges);
        for (step = 0; step < loadedEdges.length; step++) {
            loadedEdges[step] = this.fillEdge(loadedEdges[step]);
        }
        this.edges = new DataSet(loadedEdges);

        this.container = document.getElementById("outlet");
        
        this.data = {
            nodes: this.nodes,
            edges: this.edges,
        };
        var options = {};
        this.network = new Network(this.container, this.data, options);
}

Rendered HTML

<div id="outlet">
   <!-- Network is here, but not must be -->
   <div class="vis-network" tabindex="900" style="position: relative; overflow: hidden; touch-action: pan-y; user-select: none; -webkit-user-drag: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); width: 100%; height: 100%;">
      <canvas style="position: relative; touch-action: none; user-select: none; -webkit-user-drag: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); width: 100%; height: 100%;" width="1260" height="563"></canvas>
   </div>
   <flow-container-root-2521314 id="ROOT-2521314" style="">
      <vaadin-vertical-layout theme="padding spacing" id="mainview" style="width: 100%;">
         ...
         <vaadin-button tabindex="0" role="button">Add node</vaadin-button>
         <vaadin-horizontal-layout theme="spacing">
            <vaadin-upload target="VAADIN/dynamic/resource/3/c968ce30-4fc1-4e36-8d06-ddba9ecfbfd1/upload"></vaadin-upload>
            <vaadin-button disabled="" tabindex="-1" aria-disabled="true" role="button">Load data to XML</vaadin-button>
         </vaadin-horizontal-layout>
         ... 
         <div></div> <!-- Network must be here -->
         ...
      </vaadin-vertical-layout>
   </flow-container-root-2521314>
</div>
1 Answers

This happens because your component is not setting "id" of the element. And in your case there is accidentally other div with id=outlet, and your JavaScript document.getElementById("outlet"); finds it and uses it as element where it builds the Network.

I would do it this way

@JsModule("./visjs-test.js")
@NpmPackage(value = "vis", version = "0.110.0")
@Tag("div")
public class VisJs extends Composite<Div> {

    public VisJs(List<VisJsEdge> edges, List<VisJsNode> nodes) throws JsonProcessingException {
        String id=randomId(10);
        setId();
        ...
        getElement().executeJs("window.initThree($0, $1, $2)", this, jsonEdges, jsonNodes, id);
    }
    
    private String randomId(int chars) {
        int limit = (10 * chars) - 1;
        String key = "" + rand.nextInt(limit);
        key = String.format("%" + chars + "s", key).replace(' ', '0');
        return "vis-" + key;
    }

And naturally update the initThree function you have set to window to use that id parameter.

You need to have unique id for each component instance. This way you can create multiple components on the same view. Otherwise new instances would ruin the old ones.

Related