demo D226
Joining a second grid in Vue
Orders carry a customer id but no tier; a join brings it across from a customers grid, then groups revenue by tier
join: { with, on, select }
Here orders carry a customer id but no tier, and a join brings the tier across from a separate customers grid, then groups revenue by it. It lets you enrich one dataset from another and report on the combined result, without flattening the two together beforehand.
This is the Vue 3 version. A createLatticeGrid component takes the configuration through v-bind, and reactive data flows straight into the grid, so it updates the way the rest of your Vue app does.
The configuration
<link rel="stylesheet" href="https://cdn.latticegrid.dev/lattice-grid@1.108.0/lattice-grid.min.css">
<style>
#books { display: flex; gap: 16px; }
#orders { flex: 2; }
#customers { flex: 1; }
#orders > div, #customers > div { height: 300px; }
#byTier { margin-top: 16px; }
</style>
<div id="app"></div>
<script type="module">
import * as Vue from 'https://esm.sh/vue@3/dist/vue.esm-browser.prod.js';
import { createGrid } from 'https://cdn.latticegrid.dev/lattice-grid@1.108.0/lattice-grid.esm.min.js';
import createLatticeGrid from 'https://cdn.latticegrid.dev/lattice-grid@1.108.0/modules/vue.esm.min.js';
const LatticeGrid = createLatticeGrid({ vue: Vue, createGrid });
const USD = { style: 'currency', currency: 'USD', decimals: 0 };
Vue.createApp({
components: { LatticeGrid },
data() {
return {
// The two sides: orders carry a customerId, and the tier lives on the customer.
customers: {
rowKey: 'id',
columns: [{ field: 'id', title: 'ID' }, { field: 'name', title: 'Customer' }, { field: 'tier', title: 'Tier' }],
rows: customerRows, // e.g. [{ id: 'C0', name: 'Acme', tier: 'Enterprise' }, ...]
},
orders: {
rowKey: 'id',
toolPanel: { side: 'left', panels: ['filters', 'columns'] },
columns: [
{ field: 'customerId', title: 'Customer' },
{ field: 'region', title: 'Region', filter: { type: 'set' } },
{ field: 'amount', title: 'Value', type: 'number', format: USD, total: 'sum' },
],
rows: orderRows, // e.g. [{ id: 'O0', customerId: 'C0', region: 'EMEA', amount: 1240 }, ...]
},
// Built once both source grids are live, which is why it waits for mounted().
byTier: null,
};
},
mounted() {
// The join brings tier across from the customers grid onto each order, matching
// customerId to id, then the group runs on that brought-across field. It runs
// before grouping, so a group can read a field the join produced.
this.byTier = {
autoHeight: true,
source: {
// markRaw: a live grid is an instance to hand on, not reactive state.
mode: 'derived', from: Vue.markRaw(this.$refs.orders.grid()), follow: 'filtered', refresh: 'live',
join: { with: Vue.markRaw(this.$refs.customers.grid()), on: { left: 'customerId', right: 'id' }, select: ['tier'] },
groupBy: 'tier',
select: { revenue: { of: 'amount', fn: 'sum' }, orders: { fn: 'count' } },
sort: [{ col: 'revenue', dir: 'desc' }],
},
columns: [
{ field: 'tier', title: 'Tier' },
{ field: 'revenue', title: 'Revenue', type: 'number', format: USD },
{ field: 'orders', title: 'Orders', type: 'number' },
],
};
},
template: `
<div>
<div id="books">
<div id="orders"><lattice-grid ref="orders" v-bind="orders" /></div>
<div id="customers"><lattice-grid ref="customers" v-bind="customers" /></div>
</div>
<div id="byTier"><lattice-grid v-if="byTier" v-bind="byTier" /></div>
</div>
`,
}).mount('#app');
</script>