Products

Persistence

This section covers practices for saving data grid data, including the most popular techniques.

Documentation

Methods

Method Description
getRowId Get the row ID from a given row number.
getRowId(rowIndex: Number) : String | Number
setRowId Set the row ID for a given row number.
setRowId(rowIndex: Number, rowId: Number | String) : void
getRowById Get the data from a row, or the row object by ID.
getRowById(rowId: Number, element?: Boolean) : object | array

Settings

On the spreadsheet configuration level

Property Description
persistence: function A function to handle all changes in the spreadsheet
autoId: boolean Automatically generate GUID identifiers for rows

On the worksheet configuration level

Property Description
rows.id: string | number Define the unique identifier for the row

Examples

General persistence implementation

Use the persistence property to send all spreadsheet changes to your server.

<html>
<script src="https://jspreadsheet.com/v12/jspreadsheet.js"></script>
<script src="https://jsuites.net/v6/jsuites.js"></script>
<link rel="stylesheet" href="https://jspreadsheet.com/v12/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>

<script>
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('OWNmMjA2YzllYjU3NWY1MDc1YTYyMWRlN2UxMzFhYjBjNzA4OWM5YTFiMGRhNTNiN2RkZWFkYzBhYTBlMmVjMzk1NzIyZGRlYmI5NzIxNDgyZDk0ZTQzZDlmY2UyYmJkNWZhNTE4MzY3N2ZlZjNhNmU5NjYxY2IzNzFkZGJkZmMsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azJNVFl5TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');

const data = [
    {
        "title": "Unlocking Android",
        "pageCount": 416,
        "publishedDate": "2009-04-01" ,
        "authors": "W. Frank Ableson, Charlie Collins, Robi Sen",
        "categories": "Open Source;Mobile"
    },
    {
        "title": "Android in Action, Second Edition",
        "pageCount": 592,
        "publishedDate": "2011-01-14",
        "authors": "W. Frank Ableson, Robi Sen",
        "categories": "Java"
    },
    {
        "title": "Flex 3 in Action",
        "pageCount": 576,
        "publishedDate": "2009-02-02",
        "authors": "Tariq Ahmed with Jon Hirschi, Faisal Abid",
        "categories": "Internet"
    },
];

/**
 * Aggregate all the changes in the same row
 */
const aggregateRows = function(worksheet, data) {
    let rows = [];
    for (let i = 0; i < data.length; i++) {
        // Coords
        let x = data[i].x;
        let y = data[i].y;
        // Create row
        if (! rows[y]) {
            rows[y] = {
                id: worksheet.rows[y].id,
                row: y,
                data: {},
            }
        }
        // Key
        let key = worksheet.options.columns[x].name;
        // Data
        rows[y].data[key] = data[i].value;
    }

    // Filter rows
    return rows.filter(function(row) {
        return row != null;
    });
}

// Create the spreadsheet
jspreadsheet(document.getElementById('spreadsheet'), {
    worksheets: [
        {
            autoId: true,
            data: data,
            columns: [
                {
                    type: 'text',
                    title: 'Title',
                    name: 'title',
                    width: '150px',
                },
                {
                    type: 'text',
                    width: '55px',
                    title: 'Pages',
                    name: 'pageCount'
                },
                {
                    type: 'calendar',
                    width: '90px',
                    title: 'Published',
                    name: 'publishedDate'
                },
                {
                    type: 'text',
                    title: 'Author',
                    name: 'authors',
                    width: '150px',
                },
                {
                    type: 'dropdown',
                    title: 'Categories',
                    name: 'categories',
                    source: [
                        'Internet',
                        'Web Development',
                        'Java',
                        'Mobile',
                        'Open Source'
                    ],
                    width: '200px',
                    render: 'tag',
                    multiple: true
                },
            ],
            rows: [
                { id: '4ab2b86b-6b48-4234-82c9-ea614374fb0b' },
                { id: 'ce9fbb3a-2330-425d-9a81-e75b711bec8d' },
                { id: 'd57533c3-d181-4083-b999-b8bc58bbf236' }
            ]
        }
    ],
    persistence: function(worksheet, method, payload) {
        let ignore = ['setBorder', 'resetBorders' ];
        // Ignore the methods to update the borders
        if (ignore.indexOf(method) >= 0) {
            return false;
        } else {
            // Aggregate rows for the following methods
            if (method === 'setValue' || method === 'setFormula') {
                payload = aggregateRows(worksheet, payload.data)
            }
            // Create attributes to be sent
            let formData = new FormData();
            formData.append('data', JSON.stringify(payload));
            // Fetch options
            const fetchOptions = {
                method: 'POST',
                headers: {
                    'X-Requested-With': 'http',
                    'Authorization': 'Bearer your-token',
                },
                body: formData,
            };
            // Perform the fetch
            fetch('/save', fetchOptions).then(response => response.json()).then(function (result) {
                // Save your data remotely
            }).catch(function (result) {
                // Something went wrong
            });
        }
    }
});
</script>
</html>
import React, { useRef } from "react";
import { Spreadsheet, Worksheet } from "@jspreadsheet/react";
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";

// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('OWNmMjA2YzllYjU3NWY1MDc1YTYyMWRlN2UxMzFhYjBjNzA4OWM5YTFiMGRhNTNiN2RkZWFkYzBhYTBlMmVjMzk1NzIyZGRlYmI5NzIxNDgyZDk0ZTQzZDlmY2UyYmJkNWZhNTE4MzY3N2ZlZjNhNmU5NjYxY2IzNzFkZGJkZmMsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azJNVFl5TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');

/**
 * Aggregate all the changes in the same row
 */
const aggregateRows = function(worksheet, data) {
    let rows = [];
    for (let i = 0; i < data.length; i++) {
        // Coords
        let x = data[i].x;
        let y = data[i].y;
        // Create row
        if (! rows[y]) {
            rows[y] = {
                id: worksheet.rows[y].id,
                row: y,
                data: {},
            }
        }
        // Key
        let key = worksheet.options.columns[x].name;
        // Data
        rows[y].data[key] = data[i].value;
    }

    // Filter rows
    return rows.filter(function(row) {
        return row != null;
    });
}

export default function App() {
    const spreadsheet = useRef();

    // Data
    const data = [
        {
            "title": "Unlocking Android",
            "pageCount": 416,
            "publishedDate": "2009-04-01" ,
            "authors": "W. Frank Ableson, Charlie Collins, Robi Sen",
            "categories": "Open Source;Mobile"
        },
        {
            "title": "Android in Action, Second Edition",
            "pageCount": 592,
            "publishedDate": "2011-01-14",
            "authors": "W. Frank Ableson, Robi Sen",
            "categories": "Java"
        },
        {
            "title": "Flex 3 in Action",
            "pageCount": 576,
            "publishedDate": "2009-02-02",
            "authors": "Tariq Ahmed with Jon Hirschi, Faisal Abid",
            "categories": "Internet"
        },
    ];

    // Rows with IDs
    const rows = [
        { id: '4ab2b86b-6b48-4234-82c9-ea614374fb0b' },
        { id: 'ce9fbb3a-2330-425d-9a81-e75b711bec8d' },
        { id: 'd57533c3-d181-4083-b999-b8bc58bbf236' }
    ];

    // Columns
    const columns = [
        {
            type: 'text',
            title: 'Title',
            name: 'title',
            width: '150px',
        },
        {
            type: 'text',
            width: '55px',
            title: 'Pages',
            name: 'pageCount'
        },
        {
            type: 'calendar',
            width: '90px',
            title: 'Published',
            name: 'publishedDate'
        },
        {
            type: 'text',
            title: 'Author',
            name: 'authors',
            width: '150px',
        },
        {
            type: 'dropdown',
            title: 'Categories',
            name: 'categories',
            source: [
                'Internet',
                'Web Development',
                'Java',
                'Mobile',
                'Open Source'
            ],
            width: '200px',
            render: 'tag',
            multiple: true
        },
    ];

    // Persistence function
    const persistence = function(worksheet, method, payload) {
        let ignore = ['setBorder', 'resetBorders' ];
        // Ignore the methods to update the borders
        if (ignore.indexOf(method) >= 0) {
            return false;
        } else {
            // Aggregate rows for the following methods
            if (method === 'setValue' || method === 'setFormula') {
                payload = aggregateRows(worksheet, payload.data)
            }
            // Create attributes to be sent
            let formData = new FormData();
            formData.append('data', JSON.stringify(payload));
            // Fetch options
            const fetchOptions = {
                method: 'POST',
                headers: {
                    'X-Requested-With': 'http',
                    'Authorization': 'Bearer your-token',
                },
                body: formData,
            };
            // Perform the fetch
            fetch('/save', fetchOptions).then(response => response.json()).then(function (result) {
                // Save your data remotely
            }).catch(function (result) {
                // Something went wrong
            });
        }
    }

    // Render react component
    return (
        <Spreadsheet ref={spreadsheet} persistence={persistence}>
            <Worksheet autoId={true} data={data} rows={rows} columns={columns} />
        </Spreadsheet>
    );
}
<template>
    <Spreadsheet ref="spreadsheet" :persistence="persistence">
        <Worksheet :autoId="true" :data="data" :rows="rows" :columns="columns" />
    </Spreadsheet>
</template>

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

// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('OWNmMjA2YzllYjU3NWY1MDc1YTYyMWRlN2UxMzFhYjBjNzA4OWM5YTFiMGRhNTNiN2RkZWFkYzBhYTBlMmVjMzk1NzIyZGRlYmI5NzIxNDgyZDk0ZTQzZDlmY2UyYmJkNWZhNTE4MzY3N2ZlZjNhNmU5NjYxY2IzNzFkZGJkZmMsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azJNVFl5TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');

/**
 * Aggregate all the changes in the same row
 */
const aggregateRows = function(worksheet, data) {
    let rows = [];
    for (let i = 0; i < data.length; i++) {
        // Coords
        let x = data[i].x;
        let y = data[i].y;
        // Create row
        if (! rows[y]) {
            rows[y] = {
                id: worksheet.rows[y].id,
                row: y,
                data: {},
            }
        }
        // Key
        let key = worksheet.options.columns[x].name;
        // Data
        rows[y].data[key] = data[i].value;
    }

    // Filter rows
    return rows.filter(function(row) {
        return row != null;
    });
}

export default {
    components: {
        Spreadsheet,
        Worksheet,
    },
    methods: {
        // Persistence function
        persistence(worksheet, method, payload) {
            let ignore = ['setBorder', 'resetBorders' ];
            // Ignore the methods to update the borders
            if (ignore.indexOf(method) >= 0) {
                return false;
            } else {
                // Aggregate rows for the following methods
                if (method === 'setValue' || method === 'setFormula') {
                    payload = aggregateRows(worksheet, payload.data)
                }
                // Create attributes to be sent
                let formData = new FormData();
                formData.append('data', JSON.stringify(payload));
                // Fetch options
                const fetchOptions = {
                    method: 'POST',
                    headers: {
                        'X-Requested-With': 'http',
                        'Authorization': 'Bearer your-token',
                    },
                    body: formData,
                };
                // Perform the fetch
                fetch('/save', fetchOptions).then(response => response.json()).then(function (result) {
                    // Save your data remotely
                }).catch(function (result) {
                    // Something went wrong
                });
            }
        }
    },
    data() {
        // Data
        const data = [
            {
                "title": "Unlocking Android",
                "pageCount": 416,
                "publishedDate": "2009-04-01" ,
                "authors": "W. Frank Ableson, Charlie Collins, Robi Sen",
                "categories": "Open Source;Mobile"
            },
            {
                "title": "Android in Action, Second Edition",
                "pageCount": 592,
                "publishedDate": "2011-01-14",
                "authors": "W. Frank Ableson, Robi Sen",
                "categories": "Java"
            },
            {
                "title": "Flex 3 in Action",
                "pageCount": 576,
                "publishedDate": "2009-02-02",
                "authors": "Tariq Ahmed with Jon Hirschi, Faisal Abid",
                "categories": "Internet"
            },
        ];

        // Rows with IDs
        const rows = [
            { id: '4ab2b86b-6b48-4234-82c9-ea614374fb0b' },
            { id: 'ce9fbb3a-2330-425d-9a81-e75b711bec8d' },
            { id: 'd57533c3-d181-4083-b999-b8bc58bbf236' }
        ];

        // Columns
        const columns = [
            {
                type: 'text',
                title: 'Title',
                name: 'title',
                width: '150px',
            },
            {
                type: 'text',
                width: '55px',
                title: 'Pages',
                name: 'pageCount'
            },
            {
                type: 'calendar',
                width: '90px',
                title: 'Published',
                name: 'publishedDate'
            },
            {
                type: 'text',
                title: 'Author',
                name: 'authors',
                width: '150px',
            },
            {
                type: 'dropdown',
                title: 'Categories',
                name: 'categories',
                source: [
                    'Internet',
                    'Web Development',
                    'Java',
                    'Mobile',
                    'Open Source'
                ],
                width: '200px',
                render: 'tag',
                multiple: true
            },
        ];

        return {
            data,
            rows,
            columns,
        };
    }
}
</script>
import { Component, ViewChild, ElementRef } from "@angular/core";
import jspreadsheet from "jspreadsheet";
import "jspreadsheet/dist/jspreadsheet.css"
import "jsuites/dist/jsuites.css"

// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('OWNmMjA2YzllYjU3NWY1MDc1YTYyMWRlN2UxMzFhYjBjNzA4OWM5YTFiMGRhNTNiN2RkZWFkYzBhYTBlMmVjMzk1NzIyZGRlYmI5NzIxNDgyZDk0ZTQzZDlmY2UyYmJkNWZhNTE4MzY3N2ZlZjNhNmU5NjYxY2IzNzFkZGJkZmMsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azJNVFl5TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');

/**
 * Aggregate all the changes in the same row
 */
const aggregateRows = function(worksheet, data) {
    let rows = [];
    for (let i = 0; i < data.length; i++) {
        // Coords
        let x = data[i].x;
        let y = data[i].y;
        // Create row
        if (! rows[y]) {
            rows[y] = {
                id: worksheet.rows[y].id,
                row: y,
                data: {},
            }
        }
        // Key
        let key = worksheet.options.columns[x].name;
        // Data
        rows[y].data[key] = data[i].value;
    }

    // Filter rows
    return rows.filter(function(row) {
        return row != null;
    });
}

@Component({
    standalone: true,
    selector: "app-root",
    template: `<div #spreadsheet></div>`,
})
export class AppComponent {
    @ViewChild("spreadsheet") spreadsheet: ElementRef;
    // Worksheets
    worksheets: jspreadsheet.worksheetInstance[];
    // Create a new data grid
    ngAfterViewInit() {
        // Create spreadsheet
        this.worksheets = jspreadsheet(this.spreadsheet.nativeElement, {
            worksheets: [
                {
                    autoId: true,
                    data: [
                        {
                            "title": "Unlocking Android",
                            "pageCount": 416,
                            "publishedDate": "2009-04-01" ,
                            "authors": "W. Frank Ableson, Charlie Collins, Robi Sen",
                            "categories": "Open Source;Mobile"
                        },
                        {
                            "title": "Android in Action, Second Edition",
                            "pageCount": 592,
                            "publishedDate": "2011-01-14",
                            "authors": "W. Frank Ableson, Robi Sen",
                            "categories": "Java"
                        },
                        {
                            "title": "Flex 3 in Action",
                            "pageCount": 576,
                            "publishedDate": "2009-02-02",
                            "authors": "Tariq Ahmed with Jon Hirschi, Faisal Abid",
                            "categories": "Internet"
                        },
                    ],
                    columns: [
                        {
                            type: 'text',
                            title: 'Title',
                            name: 'title',
                            width: '150px',
                        },
                        {
                            type: 'text',
                            width: '55px',
                            title: 'Pages',
                            name: 'pageCount'
                        },
                        {
                            type: 'calendar',
                            width: '90px',
                            title: 'Published',
                            name: 'publishedDate'
                        },
                        {
                            type: 'text',
                            title: 'Author',
                            name: 'authors',
                            width: '150px',
                        },
                        {
                            type: 'dropdown',
                            title: 'Categories',
                            name: 'categories',
                            source: [
                                'Internet',
                                'Web Development',
                                'Java',
                                'Mobile',
                                'Open Source'
                            ],
                            width: '200px',
                            render: 'tag',
                            multiple: true
                        },
                    ],
                    rows: [
                        { id: '4ab2b86b-6b48-4234-82c9-ea614374fb0b' },
                        { id: 'ce9fbb3a-2330-425d-9a81-e75b711bec8d' },
                        { id: 'd57533c3-d181-4083-b999-b8bc58bbf236' }
                    ]
                }
            ],
            persistence: function(worksheet, method, payload) {
                let ignore = ['setBorder', 'resetBorders' ];
                // Ignore the methods to update the borders
                if (ignore.indexOf(method) >= 0) {
                    return false;
                } else {
                    // Aggregate rows for the following methods
                    if (method === 'setValue' || method === 'setFormula') {
                        payload = aggregateRows(worksheet, payload.data)
                    }
                    // Create attributes to be sent
                    let formData = new FormData();
                    formData.append('data', JSON.stringify(payload));
                    // Fetch options
                    const fetchOptions = {
                        method: 'POST',
                        headers: {
                            'X-Requested-With': 'http',
                            'Authorization': 'Bearer your-token',
                        },
                        body: formData,
                    };
                    // Perform the fetch
                    fetch('/save', fetchOptions).then(response => response.json()).then(function (result) {
                        // Save your data remotely
                    }).catch(function (result) {
                        // Something went wrong
                    });
                }
            }
        });
    }
}

Custom Row IDs

The following example demonstrates custom ID generation with action buttons embedded in the last column.

<html>
<script src="https://jspreadsheet.com/v12/jspreadsheet.js"></script>
<script src="https://jsuites.net/v6/jsuites.js"></script>
<link rel="stylesheet" href="https://jspreadsheet.com/v12/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>

<script>
const action = function() {
    let methods = {};
 
    methods.createCell = function(cell, value, x, y, instance, options) {
        let input = document.createElement('i');
        input.className = 'material-icons';
        input.style.cursor = 'pointer';
        input.style.fontSize = '22px';
        input.innerHTML = "search";
        input.onclick = function() {
            let id = instance.getRowId(y);
            // Do some action
            alert(id);
        }
 
        cell.appendChild(input);

        // Readonly
        cell.classList.add('readonly');
    }
 
    return methods;
}();

// New random GUIDs
const guid = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        let r = Math.random() * 16 | 0;
        let v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}
 
jspreadsheet(document.getElementById('spreadsheet'), {
    worksheets: [
        {
            data: [
                ['Google', '5', ''],
                ['Bing', '4', ''],
                ['Yahoo', '1', ''],
                ['Duckduckgo', '5', ''],
            ],
            columns: [
                { type: 'text', width:'400px' },
                { type: 'rating', width:'100px' },
                { type: action, width:'100px' },
            ],
            rows: [
                { id: 'cae4673d-5c11-4ece-beb0-4d89fad5510c' },
                { id: '0bb4800f-c997-4f3c-b1aa-303bc49096df' },
                { id: '52694185-722d-47cf-b35e-ffa6323ddcef' },
                { id: '370915fe-0ce0-464a-915a-cdcf1c157b20' }, 
            ]
        }
    ],
    onbeforeinsertrow: function(worksheet, rows) {
        // Generate new random GUIDs for the new rows
        return rows.map(function(v) {
            return { ...v, id: guid() };
        });
    }
});
</script>
</html>
import React, { useRef } from "react";
import { Spreadsheet, Worksheet } from "@jspreadsheet/react";
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";

// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('OWNmMjA2YzllYjU3NWY1MDc1YTYyMWRlN2UxMzFhYjBjNzA4OWM5YTFiMGRhNTNiN2RkZWFkYzBhYTBlMmVjMzk1NzIyZGRlYmI5NzIxNDgyZDk0ZTQzZDlmY2UyYmJkNWZhNTE4MzY3N2ZlZjNhNmU5NjYxY2IzNzFkZGJkZmMsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azJNVFl5TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');

const action = function() {
    const methods = {};

    methods.createCell = function(cell, value, x, y, instance, options) {
        let input = document.createElement('i');
        input.className = 'material-icons';
        input.style.cursor = 'pointer';
        input.style.fontSize = '22px';
        input.innerHTML = "search";
        input.onclick = function() {
            let id = instance.getRowId(y);
            // Do some action
            alert(id);
        }

        cell.appendChild(input);

        // Readonly
        cell.classList.add('readonly');
    }

    return methods;
}();

// New random GUIDs
const guid = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        let r = Math.random() * 16 | 0;
        let v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}

export default function App() {
    const spreadsheet = useRef();

    // Data
    const data = [
        ['Google', '5', ''],
        ['Bing', '4', ''],
        ['Yahoo', '1', ''],
        ['Duckduckgo', '5', ''],
    ];

    // Rows with IDs
    const rows = [
        { id: 'cae4673d-5c11-4ece-beb0-4d89fad5510c' },
        { id: '0bb4800f-c997-4f3c-b1aa-303bc49096df' },
        { id: '52694185-722d-47cf-b35e-ffa6323ddcef' },
        { id: '370915fe-0ce0-464a-915a-cdcf1c157b20' },
    ];

    // Event handler for before insert row
    const onbeforeinsertrow = function(worksheet, rows) {
        // Generate new random GUIDs for the new rows
        return rows.map(function(v) {
            return { ...v, id: guid() };
        });
    }

    // Columns
    const columns = [
        { type: 'text', width:'400px' },
        { type: 'rating', width:'100px' },
        { type: action, width:'100px' },
    ];

    // Render react component
    return (
        <Spreadsheet ref={spreadsheet} onbeforeinsertrow={onbeforeinsertrow}>
            <Worksheet data={data} rows={rows} columns={columns} />
        </Spreadsheet>
    );
}
<template>
    <Spreadsheet ref="spreadsheet" :onbeforeinsertrow="onbeforeinsertrow">
        <Worksheet :data="data" :rows="rows" :columns="columns" />
    </Spreadsheet>
</template>

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

// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('OWNmMjA2YzllYjU3NWY1MDc1YTYyMWRlN2UxMzFhYjBjNzA4OWM5YTFiMGRhNTNiN2RkZWFkYzBhYTBlMmVjMzk1NzIyZGRlYmI5NzIxNDgyZDk0ZTQzZDlmY2UyYmJkNWZhNTE4MzY3N2ZlZjNhNmU5NjYxY2IzNzFkZGJkZmMsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azJNVFl5TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');

const action = function() {
    const methods = {};

    methods.createCell = function(cell, value, x, y, instance, options) {
        let input = document.createElement('i');
        input.className = 'material-icons';
        input.style.cursor = 'pointer';
        input.style.fontSize = '22px';
        input.innerHTML = "search";
        input.onclick = function() {
            let id = instance.getRowId(y);
            // Do some action
            alert(id);
        }

        cell.appendChild(input);

        // Readonly
        cell.classList.add('readonly');
    }

    return methods;
}();

// New random GUIDs
const guid = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        let r = Math.random() * 16 | 0;
        let v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}

export default {
    components: {
        Spreadsheet,
        Worksheet,
    },
    methods: {
        // Event handler for before insert row
        onbeforeinsertrow(worksheet, rows) {
            // Generate new random GUIDs for the new rows
            return rows.map(function(v) {
                return { ...v, id: guid() };
            });
        }
    },
    data() {
        // Data
        const data = [
            ['Google', '5', ''],
            ['Bing', '4', ''],
            ['Yahoo', '1', ''],
            ['Duckduckgo', '5', ''],
        ];

        // Rows with IDs
        const rows = [
            { id: 'cae4673d-5c11-4ece-beb0-4d89fad5510c' },
            { id: '0bb4800f-c997-4f3c-b1aa-303bc49096df' },
            { id: '52694185-722d-47cf-b35e-ffa6323ddcef' },
            { id: '370915fe-0ce0-464a-915a-cdcf1c157b20' },
        ];

        // Columns
        const columns = [
            { type: 'text', width:'400px' },
            { type: 'rating', width:'100px' },
            { type: action, width:'100px' },
        ];

        return {
            data,
            rows,
            columns,
        };
    }
}
</script>
import { Component, ViewChild, ElementRef } from "@angular/core";
import jspreadsheet from "jspreadsheet";

import "jspreadsheet/dist/jspreadsheet.css"
import "jsuites/dist/jsuites.css"

// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('OWNmMjA2YzllYjU3NWY1MDc1YTYyMWRlN2UxMzFhYjBjNzA4OWM5YTFiMGRhNTNiN2RkZWFkYzBhYTBlMmVjMzk1NzIyZGRlYmI5NzIxNDgyZDk0ZTQzZDlmY2UyYmJkNWZhNTE4MzY3N2ZlZjNhNmU5NjYxY2IzNzFkZGJkZmMsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azJNVFl5TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');

const action = function() {
    let methods = {};

    methods.createCell = (cell, value, x, y, instance, options) => {
        let input = document.createElement('i');
        input.className = 'material-icons';
        input.style.cursor = 'pointer';
        input.style.fontSize = '22px';
        input.innerHTML = "search";
        input.onclick = function() {
            let id = instance.getRowId(y);
            // Do some action
            alert(id);
        }

        cell.appendChild(input);

        // Readonly
        cell.classList.add('readonly');
    }

    return methods;
}();

// New random GUIDs
const guid = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        let r = Math.random() * 16 | 0;
        let v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}

@Component({
    standalone: true,
    selector: "app-root",
    template: `<div #spreadsheet></div>`,
})
export class AppComponent {
    @ViewChild("spreadsheet") spreadsheet: ElementRef;
    // Worksheets
    worksheets: jspreadsheet.worksheetInstance[];
    // Create a new data grid
    ngAfterViewInit() {
        // Create spreadsheet
        this.worksheets = jspreadsheet(this.spreadsheet.nativeElement, {
            worksheets: [{
                data: [
                    ['Google', '5', ''],
                    ['Bing', '4', ''],
                    ['Yahoo', '1', ''],
                    ['Duckduckgo', '5', ''],
                ],
                columns: [
                    { type: 'text', width:'400px' },
                    { type: 'rating', width:'100px' },
                    { type: action, width:'100px' },
                ],
                rows: [
                    { id: 'cae4673d-5c11-4ece-beb0-4d89fad5510c' },
                    { id: '0bb4800f-c997-4f3c-b1aa-303bc49096df' },
                    { id: '52694185-722d-47cf-b35e-ffa6323ddcef' },
                    { id: '370915fe-0ce0-464a-915a-cdcf1c157b20' },
                ],
            }],
            onbeforeinsertrow: function(worksheet, rows) {
                // Generate new random GUIDs for the new rows
                return rows.map(function(v) {
                    return { ...v, id: guid() };
                });
            }
        });
    }
}