dupontbertrand:gridstack

v0.1.0•Published yesterday

dupontbertrand:gridstack

A Blaze component for gridstack.js: drag-and-drop, resizable grid layouts driven by reactive data.

1{{> gridStack items=widgets itemTemplate="card" options=gridOptions onChange=onLayoutChange}}

You pass the items, the component keeps the grid in line with them: items that appear are added, items that disappear are removed, items whose position changes are moved. When the user drags or resizes, onChange gets the new layout. Changes made by another client (another tab, another user) show up live.

Meteor 3, Blaze 3, gridstack 14 (bundled, no npm install needed). Works with or without jQuery: the component does not use it, and it is tested on Blaze 3.1 without jQuery, Blaze 3.1 with jQuery, and Blaze 3.0 (which requires jQuery).

Install

meteor add dupontbertrand:gridstack

Usage

1<template name="dashboard">
2  {{> gridStack items=widgets itemTemplate="card" options=gridOptions onChange=onLayoutChange}}
3</template>
4
5<template name="card">
6  <div class="card">{{title}}</div>
7</template>
1import 'meteor/dupontbertrand:gridstack';
2
3Template.dashboard.helpers({
4  widgets: () => Widgets.find().map(({ _id, ...widget }) => ({ id: _id, ...widget })),
5  gridOptions: () => ({ column: 12, cellHeight: 80, margin: 8 }),
6  onLayoutChange() {
7    return (layout) => Meteor.callAsync('widgets.saveLayout', layout);
8  },
9});

Parameters

ParameterDescription
itemsArray of { id, x, y, w, h, ... }. Reactive. Any GridStackWidget field (minW, maxH, noResize, locked...) is passed through. Each item is also the data context of its itemTemplate, and that data stays reactive.
itemTemplateName of the template rendered inside each item.
optionsGridStackOptions, read once when the grid is created.
onChange(layout)Called after the user moves or resizes items, with [{ id, x, y, w, h }] for every item. Not called for changes that come from items, so saving the layout does not loop.
onReady(grid)Receives the GridStack instance, for anything the component does not cover (grid.willItFit(), grid.engine.findEmptyPosition()...).

GridStack is also exported: import { GridStack } from 'meteor/dupontbertrand:gridstack'.

How it works

gridstack creates, moves and removes the item elements itself, so the component never renders them with {{#each}}: Blaze and gridstack would fight over the same DOM nodes. The component adds items through the gridstack API and renders itemTemplate inside each item's content element with Blaze.renderWithData. Views are removed when their item goes away and when the component is destroyed.

Tests

./test.sh

Runs the tests in a headless Chromium with meteortesting:mocha and Playwright, once per setup: Blaze 3.1 without jQuery, Blaze 3.1 with jQuery, Blaze 3.0 with jQuery. Playwright and jQuery are installed once in ~/.cache/blaze-gridstack-test-runner, outside the package, because Meteor treats a node_modules directory inside a package as part of the package.

License

MIT