0

I'm trying to programmatically add an imported vue to a new Golden Layout pane. I've use the drag and drop example to build upon, but it is only adding HTML to the pane, not a vue that requires props passed to it, such as the pane width and height. https://golden-layout.com/tutorials/dynamically-adding-components.html

I've been trying to add it via the layout.registerComponent(), with containter.on("open", funtion, ect. but can't find:

  1. the element to mount the vue onto.
  2. the new dragged-and-dropped pane width and height.

As far as the docs say, on "open" should fire after the new pane/container is created. https://golden-layout.com/docs/Container.html#Events

However, as I've (erroneously?) implemented it the pane/container is not yet added when on "open"

The same vue is added to the default layout upon layout.init(); without an issue and works flawlessly.

But adding the same vue via the drag and drop method (as currently implemented) does not work and ends up with the following:

[Vue warn]: Cannot find element: #priceChart2

I've been doing my research and so far, can't figure out the solution.

import "./goldenlayout-base.css";
import "./goldenlayout-dark-theme.css";
// required for dynamic component instantiation from the config
import Vue from "vue";
import $ from "jquery";
import GoldenLayout from "./goldenlayout.js";

// import a price chart
import PriceChart from "src/components/TradingVueJs/Chart.vue"

let chartCnt = 1

export default {
  name: "Trader",
  props: {},
  components: {},
  computed: {},
  data() {
    return {};
  },
  mounted() {
    var config = {
      content: [
        {
          type: "column",
          isClosable: true,
          reorderEnabled: true,
          title: "",
          content: [
            {
              type: "stack",
              width: 100,
              height: 50,
              isClosable: true,
              reorderEnabled: true,
              title: "",
              activeItemIndex: 0,
              content: [
                {
                  type: "component",
                  componentName: "priceChart",
                  componentState: {
                    text: "Price Chart",
                  },
                  isClosable: true,
                  reorderEnabled: true,
                  title: "Chart",
                  id: "Chart1"
                },
              ],
            },
            {
              type: "stack",
              header: {},
              isClosable: true,
              reorderEnabled: true,
              title: "",
              activeItemIndex: 0,
              height: 50,
              content: [
                {
                  type: "component",
                  componentName: "example",
                  componentState: {
                    text: "Some message",
                  },
                  isClosable: false,
                  reorderEnabled: true,
                  title: "Example",
                  id: "Example",
                },
              ],
            },
          ],
        },
      ],
    };

    var layout = new GoldenLayout(config, $("#layoutContainer"));

    layout.registerComponent("example", function(container, state) {
      container.getElement().html("<h2>" + state.text + "</h2>");
    });


   layout.registerComponent("priceChart", function(container, state) {
      
      let id = "priceChart"+chartCnt++
      container.on("open", () => {
        container.getElement().html("<div id='"+id+"' class='chartComponent'></div>");
        // mount price chart component
        const chart = Vue.extend(PriceChart);
        const Chart = new chart({ 
          propsData: { 
            id: id,
            width: container.width, 
            height: container.height 
            } 
        });
        Chart.$mount('#'+id)
      })
    });

    //  Update GL on window resize
    window.addEventListener("resize", () => {
      layout.updateSize();
    });

    // attach the state change listener
    layout.on("stateChanged", () => {
      this.onLayoutStateChanged(layout.toConfig());
    });

    layout.init();

    var addMenuItem = function(component, title, text) {
      var element = $("<li>" + text + "</li>");
      $("#menuContainer").append(element);

      var newItemConfig = {
        title: title,
        type: "component",
        componentName: component,
        componentState: { text: text },
      };

      layout.createDragSource(element, newItemConfig);
    };

    addMenuItem("priceChart", "BTC/USDT", "Price Chart");
    addMenuItem("example", "Add me!", "You've added me!");
    addMenuItem("example", "Me too!", "You've added me too!");
  },

  methods: {
    resetLayout() {
      window.location.reload(true);
    },
    onLayoutStateChanged(state) {
      var layoutState = JSON.stringify(state, null, 2);
      // eslint-disable-next-line no-console
      console.log("changed state", layoutState);
    }
  }
};
<template>
  <!--  this is the golden-layout container where all the vue components will be contained -->
  <div id="wrapper">
    <ul id="menuContainer"></ul>
    <div id="layoutContainer"></div>
  </div>
</template>

1 Answer 1

0

In the end I had to use a setInterval() to wait for the element to appear in the DOM.

I found a great solution here:

https://gist.github.com/chrisjhoughton/7890303#gistcomment-2638757

/**
 * Wait for the specified element to appear in the DOM. When the element appears,
 * provide it to the callback. If waiting times out, send null to the callback.
 *
 * @param selector a jQuery selector (eg, 'div.container img')
 * @param callback function that takes selected element (null if timeout)
 * @param maxtries number of times to try (return null after maxtries, false to disable, if 0 will still try once)
 * @param interval ms wait between each try
 */
waitForEl(selector, callback, maxtries = false, interval = 100) {
  const poller = setInterval(() => {
    const el = jQuery(selector)
    const retry = maxtries === false || maxtries-- > 0
    if (retry && el.length < 1) return // will try again
    clearInterval(poller)
    callback(el || null)
  }, interval)
}

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.