Meta Information

Store and manage hidden metadata for individual cells programmatically. Meta-information enables attaching custom data to cells without affecting their visible content or user interface.

What's new with Version 13

  • Values: setMeta stores 0 and false as given; only undefined becomes an empty string
  • Validation: invalid cell names or cells beyond the grid return false instead of throwing, and a batch applies its valid entries. Only the applied entries reach connected users

Documentation

Methods

The following methods provide programmatic control over cell meta information:

Method Description
getMeta Get meta information from a specific cell or all cells. A cell without meta information returns undefined.
getMeta('A1') or getMeta() for all
getMeta(cellName?: string) => object | undefined
setMeta Set meta information for single or multiple cells. With a cell name, key is required. 0 and false are stored as given; only undefined becomes an empty string. Invalid cell names or cells beyond the grid are skipped and a batch applies its valid entries. Returns false when nothing was applied or the worksheet is not editable.
setMeta('A1', 'key', 'value') or setMeta({A1: {key: 'value'}})
setMeta(cellName: string | object, key?: string, value?: any) => void | false
resetMeta Reset meta information for one cell, several cells or all cells. Returns false when the worksheet is not editable.
resetMeta('A1'), resetMeta(['A1', 'B2']) or resetMeta() for all
resetMeta(cellNames?: string | string[]) => void | false

Events

Event Description
onchangemeta Triggered by setMeta. meta maps each cell name to the keys changed in that call, not to the whole meta information of the cell.
onchangemeta(worksheet: object, meta: object) => void
onresetmeta Triggered by resetMeta. cellNames is the array of cell names given to resetMeta (a single name is wrapped in an array), or undefined when resetMeta was called without arguments.
onresetmeta(worksheet: object, cellNames: string[] | undefined) => void

Configuration

Property Description
meta: object Worksheet option. Initial meta information object with cell names as keys. Example: { A1: { id: 1 } }

Examples

Meta Information Management

This example demonstrates programmatic cell metadata management using the getMeta, setMeta, and resetMeta methods.

See this example on JSFiddle

<html>
<script src="https://jspreadsheet.com/v13/jspreadsheet.js"></script>
<script src="https://jsuites.net/v6/jsuites.js"></script>
<link rel="stylesheet" href="https://jspreadsheet.com/v13/jspreadsheet.css" type="text/css" />
<link rel="stylesheet" href="https://jsuites.net/v6/jsuites.css" type="text/css" />

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />

<div id="spreadsheet"></div>

<p><textarea id='console' style='width:100%;height:80px;'></textarea></p>

<input type="button" id="btn1" value="Set meta data for multiple cells"/><br/><br/>
<input type="button" id="btn2" value="Set meta information for B2"/><br/><br/>
<input type="button" id="btn3" value="Reset meta information for A1, B2, C2"/><br/><br/>
<input type="button" id="btn4" value="Get meta information for A1"/><br/><br/>
<input type="button" id="btn5" value="Get all meta information"/><br/><br/>

<script>
// You can use the following license for quick testing on localhost, StackBlitz, or CodeSandbox.
// The license is valid for one day, after which the spreadsheet will become read-only.
// For a longer trial period, you can create a free account and generate a demo license with an extended expiration date.
jspreadsheet.setLicense('NGY3Mjg3MzZkMTFiNGIwZjI5MzdhOGY3OThiN2Y2ODI2MmNlZTc0YmU1MjYzNDllNGMwYTY3ODgxMzg1ZTNiNWQ0ZDkzMGYwM2Q4MTQxZTZkNTlmNmE1NDUyMzlhMjMyNDg4MmM4ZWExZWU2NDMyNGFhYWNjM2RjNjEzNDViMGYsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94Tnprek5EazNOelEyTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=');

// Create the spreadsheet
let table = jspreadsheet(document.getElementById('spreadsheet'), {
    worksheets: [{
        data: [
            ['US', 'Apples', 'Yes', '2019-02-12'],
            ['CA;US;UK', 'Carrots', 'Yes', '2019-03-01'],
            ['CA;BR', 'Oranges', 'No', '2018-11-10'],
            ['BR', 'Coconuts', 'Yes', '2019-01-12'],
        ],
        columns: [
            {
                type: 'dropdown',
                title: 'Product Origin',
                width: '300px',
                url: 'https://jspreadsheet.com/jspreadsheet/countries/1',
                autocomplete: true,
                multiple: true
            },
            { type: 'text', title: 'Description', width: '200px' },
            { type: 'dropdown', title: 'Stock', width: '100px', source: ['No','Yes'] },
            { type: 'calendar', title: 'Best before', width: '100px' },
        ],
        meta:{
            A1: { myMeta: 'this is just a test', otherMetaInformation: 'other test' },
            A2: { info: 'test' }
        },
    }]
});

document.getElementById("btn1").onclick = () => table[0].setMeta({ C1: { id:'1', y:'2019' }, C2: { id:'2' } });
document.getElementById("btn2").onclick = () => table[0].setMeta('B2', 'myMetaData', prompt('myMetaData:'));
document.getElementById("btn3").onclick = () => table[0].resetMeta(['A1','B2','C2'])
document.getElementById("btn4").onclick = () => document.getElementById('console').value = JSON.stringify(table[0].getMeta('A1'));
document.getElementById("btn5").onclick = () => document.getElementById('console').value  = JSON.stringify(table[0].getMeta());
</script>
</html>
import React, {useRef} from "react";
import {Spreadsheet, Worksheet, jspreadsheet} from "@jspreadsheet/react";
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";

// You can use the following license for quick testing on localhost, StackBlitz, or CodeSandbox.
// The license is valid for one day, after which the spreadsheet will become read-only.
// For a longer trial period, you can create a free account and generate a demo license with an extended expiration date.
jspreadsheet.setLicense('NGY3Mjg3MzZkMTFiNGIwZjI5MzdhOGY3OThiN2Y2ODI2MmNlZTc0YmU1MjYzNDllNGMwYTY3ODgxMzg1ZTNiNWQ0ZDkzMGYwM2Q4MTQxZTZkNTlmNmE1NDUyMzlhMjMyNDg4MmM4ZWExZWU2NDMyNGFhYWNjM2RjNjEzNDViMGYsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94Tnprek5EazNOelEyTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=');

export default function App() {
    // Spreadsheet array of worksheets
    const spreadsheet = useRef();
    const console = useRef();
    // Data
    const data = [
        ['US', 'Apples', 'Yes', '2019-02-12'],
        ['CA;US;UK', 'Carrots', 'Yes', '2019-03-01'],
        ['CA;BR', 'Oranges', 'No', '2018-11-10'],
        ['BR', 'Coconuts', 'Yes', '2019-01-12'],
    ];
    // Columns
    const columns = [
        {
            type: 'dropdown',
            title: 'Product Origin',
            width: '300px',
            url: 'https://jspreadsheet.com/jspreadsheet/countries/1',
            autocomplete: true,
            multiple: true
        },
        {type: 'text', title: 'Description', width: '200px'},
        {type: 'dropdown', title: 'Stock', width: '100px', source: ['No', 'Yes']},
        {type: 'calendar', title: 'Best before', width: '100px'},
    ];
    // Meta information
    const meta = {
        A1: {myMeta: 'this is just a test', otherMetaInformation: 'other test'},
        A2: {info: 'test'}
    }

    let style = {width: '100%', height: '80px'}

    // Render component
    return (
        <>
            <Spreadsheet ref={spreadsheet}>
                <Worksheet data={data} columns={columns} meta={meta}/>
            </Spreadsheet>
            <textarea ref={console} style={style}></textarea>
            <input type="button" value="Set meta data for multiple cells"
                    onClick={() => spreadsheet.current[0].setMeta({C1: {id: '1', y: '2019'}, C2: {id: '2'}})}/>
            <input type="button" value="Set meta information for B2"
                    onClick={() => spreadsheet.current[0].setMeta('B2', 'myMetaData', prompt('myMetaData:'))}/>
            <input type="button" value="Reset meta information for A1, B2, C2"
                    onClick={() => spreadsheet.current[0].resetMeta(['A1', 'B2', 'C2'])}/>
            <input type="button" value="Get meta information for A1"
                    onClick={() => console.current.value = JSON.stringify(spreadsheet.current[0].getMeta('A1'))}/>
            <input type="button" value="Get all meta information"
                    onClick={() => console.current.value = JSON.stringify(spreadsheet.current[0].getMeta())}/>
        </>
    );
}
<template>
  <Spreadsheet ref="spreadsheet">
    <Worksheet :data="data" :columns="columns" :meta="meta" />
  </Spreadsheet>
  <textarea ref="log" style="width: 100%; height: 80px"></textarea>
  <input type="button" value="Set meta data for multiple cells" @click="handleSetMultipleMeta" />
  <input type="button" value="Set meta information for B2" @click="handleSetB2Meta" />
  <input type="button" value="Reset meta information for A1, B2, C2" @click="handleResetMeta" />
  <input type="button" value="Get meta information for A1" @click="handleGetA1Meta" />
  <input type="button" value="Get all meta information" @click="handleGetAllMeta" />
</template>

<script>
import { Spreadsheet, Worksheet, jspreadsheet } from '@jspreadsheet/vue';
import 'jsuites/dist/jsuites.css';
import 'jspreadsheet/dist/jspreadsheet.css';

// You can use the following license for quick testing on localhost, StackBlitz, or CodeSandbox.
// The license is valid for one day, after which the spreadsheet will become read-only.
// For a longer trial period, you can create a free account and generate a demo license with an extended expiration date.
jspreadsheet.setLicense('NGY3Mjg3MzZkMTFiNGIwZjI5MzdhOGY3OThiN2Y2ODI2MmNlZTc0YmU1MjYzNDllNGMwYTY3ODgxMzg1ZTNiNWQ0ZDkzMGYwM2Q4MTQxZTZkNTlmNmE1NDUyMzlhMjMyNDg4MmM4ZWExZWU2NDMyNGFhYWNjM2RjNjEzNDViMGYsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94Tnprek5EazNOelEyTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=');

export default {
  components: {
    Spreadsheet,
    Worksheet,
  },
  data() {
    // Data
    const data = [
      ['US', 'Apples', 'Yes', '2019-02-12'],
      ['CA;US;UK', 'Carrots', 'Yes', '2019-03-01'],
      ['CA;BR', 'Oranges', 'No', '2018-11-10'],
      ['BR', 'Coconuts', 'Yes', '2019-01-12'],
    ];
    // Columns
    const columns = [
      {
        type: 'dropdown',
        title: 'Product Origin',
        width: '300px',
        url: 'https://jspreadsheet.com/jspreadsheet/countries/1',
        autocomplete: true,
        multiple: true,
      },
      { type: 'text', title: 'Description', width: '200px' },
      {
        type: 'dropdown',
        title: 'Stock',
        width: '100px',
        source: ['No', 'Yes'],
      },
      { type: 'calendar', title: 'Best before', width: '100px' },
    ];
    // Meta information
    const meta = {
      A1: { myMeta: 'this is just a test', otherMetaInformation: 'other test' },
      A2: { info: 'test' },
    };

    return {
      data,
      columns,
      meta,
    };
  },
  methods: {
    // Extracted functions
    handleSetMultipleMeta() {
      this.$refs.spreadsheet.current[0].setMeta({
        C1: { id: '1', y: '2019' },
        C2: { id: '2' },
      });
    },

    handleSetB2Meta() {
      this.$refs.spreadsheet.current[0].setMeta(
        'B2',
        'myMetaData',
        prompt('myMetaData:')
      );
    },

    handleResetMeta() {
      this.$refs.spreadsheet.current[0].resetMeta(['A1', 'B2', 'C2']);
    },

    handleGetA1Meta() {
      this.$refs.log.value = JSON.stringify(
        this.$refs.spreadsheet.current[0].getMeta('A1')
      );
    },

    handleGetAllMeta() {
      this.$refs.log.value = JSON.stringify(
        this.$refs.spreadsheet.current[0].getMeta()
      );
    },
  },
};
</script>
// @ts-nocheck
import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import jspreadsheet from 'jspreadsheet';
import 'jsuites/dist/jsuites.css';
import 'jspreadsheet/dist/jspreadsheet.css';

// You can use the following license for quick testing on localhost, StackBlitz, or CodeSandbox.
// The license is valid for one day, after which the spreadsheet will become read-only.
// For a longer trial period, you can create a free account and generate a demo license with an extended expiration date.
jspreadsheet.setLicense('NGY3Mjg3MzZkMTFiNGIwZjI5MzdhOGY3OThiN2Y2ODI2MmNlZTc0YmU1MjYzNDllNGMwYTY3ODgxMzg1ZTNiNWQ0ZDkzMGYwM2Q4MTQxZTZkNTlmNmE1NDUyMzlhMjMyNDg4MmM4ZWExZWU2NDMyNGFhYWNjM2RjNjEzNDViMGYsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94Tnprek5EazNOelEyTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=');

// Create component
@Component({
  standalone: true,
  selector: 'app-root',
  template: `
        <div #spreadsheet></div>
        <textarea #log style='width:100%;height:80px;'></textarea>
        <button type="button" (click)="handleSetMultipleMeta()">Set meta data for multiple cells</button>
        <button type="button" (click)="handleSetB2Meta()">Set meta information for B2</button>
        <button type="button" (click)="handleResetMeta()">Reset meta information for A1, B2, C2</button>
        <button type="button" (click)="handleGetA1Meta()">Get meta information for A1</button>
        <button type="button" (click)="handleGetAllMeta()">Get all meta information</button>
    `,
})
export class AppComponent implements AfterViewInit {
  @ViewChild('spreadsheet') spreadsheet: ElementRef;
  @ViewChild('log') log: ElementRef;
  // Worksheets
  worksheets: jspreadsheet.worksheetInstance[];

  // Extracted functions
  handleSetMultipleMeta() {
    this.worksheets[0].setMeta({ C1: { id: '1', y: '2019' }, C2: { id: '2' } });
  }

  handleSetB2Meta() {
    let metadata = prompt('myMetaData:');
    this.worksheets[0].setMeta('B2', 'myMetaData', metadata || '');
  }

  handleResetMeta() {
    this.worksheets[0].resetMeta(['A1', 'B2', 'C2']);
  }

  handleGetA1Meta() {
    this.log.nativeElement.value = JSON.stringify(
      this.worksheets[0].getMeta('A1')
    );
  }

  handleGetAllMeta() {
    this.log.nativeElement.value = JSON.stringify(this.worksheets[0].getMeta());
  }

  // Create a new data grid
  ngAfterViewInit() {
    // Create spreadsheet
    this.worksheets = jspreadsheet(this.spreadsheet.nativeElement, {
      worksheets: [
        {
          data: [
            ['US', 'Apples', 'Yes', '2019-02-12'],
            ['CA;US;UK', 'Carrots', 'Yes', '2019-03-01'],
            ['CA;BR', 'Oranges', 'No', '2018-11-10'],
            ['BR', 'Coconuts', 'Yes', '2019-01-12'],
          ],
          columns: [
            {
              type: 'dropdown',
              title: 'Product Origin',
              width: 300,
              url: 'https://jspreadsheet.com/jspreadsheet/countries/1',
              autocomplete: true,
              multiple: true,
            },
            { type: 'text', title: 'Description', width: 200 },
            {
              type: 'dropdown',
              title: 'Stock',
              width: 100,
              source: ['No', 'Yes'],
            },
            { type: 'calendar', title: 'Best before', width: 100 },
          ],
          meta: {
            A1: {
              myMeta: 'this is just a test',
              otherMetaInformation: 'other test',
            },
            A2: { info: 'test' },
          },
        },
      ],
    });
  }
}