Adding svelte component to gridstack

1.3k views Asked by At

I'm trying to use Svelte with gridstack. But when I add my Svelte component in js it doesn't show up right. This adds a button, but the styling isn't working and the output isn't printed to the log.

<script>
  import { onMount } from "svelte";
  import Button from "./Button.svelte";
  import GridStack from "gridstack/dist/gridstack.all.js";
  import "gridstack/dist/gridstack.min.css";

  onMount(() => {
    var grid = GridStack.init();
    grid.addWidget({ width: 2, content: "<p>Hello</p>" });
    grid.addWidget({ width: 2, content: "<Button />" });
  });
</script>

<style>
</style>

<div class='grid-stack'></div>

Full example: https://codesandbox.io/s/gallant-roentgen-jmnis?file=/App.svelte

2

There are 2 answers

0
ValarDohaeris On

As Rich mentioned in his comment, you cannot use a Svelte component inside a string that is interpreted as HTML by gridstack.js at runtime. In order for the Svelte compiler to do its magic, the component has to be part of the markup, not inside a string.

So for example, this would be how to add the button component below the gridstack container:

<div class='grid-stack'></div>
<Button />

Now that we have the interactive <Button />, we just need to figure out how move it inside the grid stack.

Luckily, the gridstack addWidget function can also accept a DOM node instead of an HTML string, so we can do something like this:

let elementWhichContainsButton; // TODO get a reference to the parent of <Button />
const widget = grid.addWidget(elementWhichContainsButton.firstChild, { width: 2 });

One way to achieve this is to use a Svelte action.

There is some extra logic (wrapping grid in a Promise and using {#await ...}) to make sure that the widget is not added before the grid has been initialized:

<script>
  /* ... imports go here ... */

  const gridPromise = new Promise(resolve => {
    onMount(() => {
      const grid = GridStack.init();
      grid.addWidget({ width: 2, content: "<p>Hello</p>" });
      resolve(grid);
    });
  });

  function addToGrid(element, grid) {
    grid.addWidget(element.firstChild, { width: 2 });
  }
</script>

<div class='grid-stack'></div>

{#await gridPromise then grid}
  <div use:addToGrid={grid}>
    <div><Button /></div>
  </div>
{/await}

A proper solution should probably also remove the element from the grid when it is removed from the DOM. According to the Svelte action documentation, this can be achieved by returning a destroy() method:

function addToGrid(element, grid) {
  const widget = grid.addWidget(element.firstChild, { width: 2 });

  return {
    destroy() {
      grid.removeWidget(widget);
    }
  };
}

A full demo of the solution is available here: https://codesandbox.io/s/mystifying-field-x2mkr?file=/App.svelte

0
user1598814 On

In GridStack version 3+, based on the answer of ValarDohaeriss, I did little important modifications, that needed for GridStack 3+.

Changes in imports :

    import "gridstack/dist/gridstack.min.css";
    import GridStack from "gridstack/dist/gridstack-h5";
    import "gridstack/dist/h5/gridstack-dd-native"; //  HTML5 drag&drop
  1. Use "w" instead of "width"

  2. You must add the HTML element ( = i.e the svelte component) manually to the GridStack element. And afterwards - inform GridStack that new element was added. Here is the new function with the changs :


        function addToGrid(element, grid) {
            // In GridStack 3 we use "w" instead of "width"
            const widget = grid.addWidget(element.firstChild, { w: 1, h: 2, y: 3, x: 4 });
            // We set an id for this widget
            widget.id = "abc";
            // Then we append it manually to GridStack html element
            grid.el.appendChild(widget);
            // And then - we inform GridStack, that a new element is added.
            grid.makeWidget("#abc");
    
            return {
              destroy() {
                 grid.removeWidget(widget);
             }
    
          };
    
        }

Full example with GridStack 3.2.0 is available here : https://codesandbox.io/s/great-worker-yq2e9?file=/App.svelte:786-1292