dupontbertrand:gridstack

v0.2.0•Published last month

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 12, 13 or 14. gridstack is not bundled: your app installs it from npm, so you get its updates and security fixes straight from npm, and npm audit sees it. 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
meteor npm install gridstack

The package checks the installed gridstack version at startup (tmeasday:check-npm-versions) and warns if it is missing or outside the supported range.

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 and Blaze 3.0 with jQuery on gridstack 14, then gridstack 13 and 12 on Blaze 3.1. Playwright, jQuery and gridstack are installed 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