Collaboration
Two users editing the same spreadsheet in real time. Both grids below are connected to the same document on Jspreadsheet Server: a change in one appears in the other, and in every browser that has this page open. Teams work together on one spreadsheet, like Google Sheets, embedded in your own application.
<!DOCTYPE html>
<html lang="pt-BR">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jspreadsheet@13/dist/jspreadsheet.min.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/css2?family=Inter:wght@400;500;600;700&family=Material+Icons&display=swap" />
<script src="https://jsuites.net/v6/jsuites.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jspreadsheet@13/dist/index.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@lemonadejs/studio/dist/index.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@jspreadsheet/client/dist/index.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/socket.io@4.7.5/client-dist/socket.io.min.js"></script>
<style>
.collab { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; padding: 20px; background: #f6f7fb; font-family: Inter, -apple-system, "Segoe UI", Roboto, sans-serif; }
.collab-panel { min-width: 0; background: #fff; border: 1px solid #e5e7eb; box-shadow: 0 4px 14px rgba(17, 24, 39, .05); }
.collab-head { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid #e5e7eb; font-size: 13px; color: #1f2937; }
.collab-head b { font-weight: 600; }
.collab-head span { color: #6b7280; margin-left: auto; font-size: 12px; }
.collab-avatar { width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; color: #fff; font-weight: 600; font-size: 12px; }
.collab-sheet { padding: 12px; overflow-x: auto; }
.collab-sheet .jss_container { vertical-align: top; }
.collab-hint { text-align: center; font-size: 13px; color: #6b7280; margin: 14px 0 0; }
@media (max-width: 900px) { .collab { grid-template-columns: 1fr; } }
</style>
<div class="collab">
<div class="collab-panel">
<div class="collab-head">
<div class="collab-avatar" style="background: #2563eb">A</div>
<b>Alice</b><span>Browser 1</span>
</div>
<div class="collab-sheet"><div id="sheetA"></div></div>
</div>
<div class="collab-panel">
<div class="collab-head">
<div class="collab-avatar" style="background: #ea580c">B</div>
<b>Bob</b><span>Browser 2</span>
</div>
<div class="collab-sheet"><div id="sheetB"></div></div>
</div>
</div>
<p class="collab-hint">
Type in either sheet: the change travels through
<a href="/products/server">Jspreadsheet Server</a> and appears in the other one, and in every
browser that has this page open.
</p>
<script>
(function () {
const GUID = '4b9e6f12-8c3a-4d57-b1e0-6a2f9c8d7e31';
const SERVER_URL = 'https://jspreadsheet.com';
const SERVER_PATH = 's/';
let remote;
let instances = [];
function removeImageButton(toolbarOptions) {
for (let i = 0; i < toolbarOptions.items.length; i++) {
if (toolbarOptions.items[i].content === 'add_photo_alternate') {
toolbarOptions.items.splice(i, 1);
i--;
}
}
return toolbarOptions;
}
function init() {
if (window.jspreadsheet && typeof jspreadsheet.destroyAll === 'function') {
jspreadsheet.destroyAll();
}
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('M2Q1MmFiODIzMTJjZjVhY2I5ZTBlMDA3MmJhNzQ0YzlhNDUwZjAyYjcwNjc2MTZlYWU3ZTAwOGJjNjQ1NTBlNTJlNjU2NzZjNjMxNjQ3MGRiMjkyZmFhYzFjZjVkOTY2MDg0MTExZThiZTU0NWRjZTU2MWVlZWM5MDdmZjMyNDIsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpreE56QTFPVGs0TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=');
jspreadsheet.setExtensions({ formula, client });
remote = client.connect({
url: SERVER_URL,
path: SERVER_PATH,
});
// Created by the first visitor; afterwards the document already exists
const created = remote.create(GUID, {
tabs: false,
toolbar: true,
worksheets: [{
worksheetName: 'Sprint',
minDimensions: [6, 12],
columns: [
{ title: 'Task', width: 170 },
{ title: 'Owner', width: 90 },
{ title: 'Status', width: 100, type: 'dropdown', source: ['To do', 'Doing', 'Done'] },
{ title: 'Due', width: 100, type: 'calendar', options: { format: 'DD/MM/YYYY' } },
{ title: 'Hours', width: 70, type: 'numeric' },
{ title: 'Done', width: 60, type: 'checkbox' },
],
data: [
['Landing page copy', 'Alice', 'Doing', '2026-10-12', 6, false],
['Pricing table', 'Bob', 'To do', '2026-10-14', 4, false],
['Signup flow', 'Alice', 'Done', '2026-10-08', 8, true],
['Email templates', 'Bob', 'Doing', '2026-10-15', 5, false],
['Analytics events', 'Alice', 'To do', '2026-10-18', 3, false],
['Total', '', '', '', '=SUM(E1:E5)', ''],
],
style: { A6: 'font-weight: bold', E6: 'font-weight: bold' },
}],
});
const commonOptions = {
guid: GUID,
toolbar: removeImageButton,
onbeforeloadimage: function () {
return '/templates/default/img/blocked.png';
},
};
const elA = document.getElementById('sheetA');
const elB = document.getElementById('sheetB');
// Open both grids once the document exists
Promise.resolve(created).catch(function() {}).then(function() {
instances.push(jspreadsheet(elA, commonOptions));
instances.push(jspreadsheet(elB, commonOptions));
});
}
function cleanup() {
if (window.jspreadsheet && typeof jspreadsheet.destroyAll === 'function') {
jspreadsheet.destroyAll();
}
instances = [];
}
init();
window.addEventListener('beforeunload', cleanup);
})();
</script>
</html>
import React, { useRef, useEffect } from 'react';
import { Spreadsheet, jspreadsheet } from '@jspreadsheet/react';
import formula from '@jspreadsheet/formula-pro';
import client from '@jspreadsheet/client';
export default function JSServerMirror() {
const GUID = "4b9e6f12-8c3a-4d57-b1e0-6a2f9c8d7e31";
const SERVER_URL = "https://jspreadsheet.com";
const SERVER_PATH = "s/";
const maxParentWidth = 1300;
const sheetMaxWidth = 600;
const sheetHeight = 300;
const sheetARef = useRef(null);
const sheetBRef = useRef(null);
useEffect(() => {
if (!window.jspreadsheet) {
console.error("jspreadsheet is not available on window.");
return;
}
const { jspreadsheet } = window;
const { formula, client } = window;
if (typeof jspreadsheet.destroyAll === "function") {
jspreadsheet.destroyAll();
}
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('M2Q1MmFiODIzMTJjZjVhY2I5ZTBlMDA3MmJhNzQ0YzlhNDUwZjAyYjcwNjc2MTZlYWU3ZTAwOGJjNjQ1NTBlNTJlNjU2NzZjNjMxNjQ3MGRiMjkyZmFhYzFjZjVkOTY2MDg0MTExZThiZTU0NWRjZTU2MWVlZWM5MDdmZjMyNDIsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpreE56QTFPVGs0TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=');
if (typeof jspreadsheet.setExtensions === "function") {
jspreadsheet.setExtensions({ formula, client });
}
const remote = client.connect({ url: SERVER_URL, path: SERVER_PATH });
remote.create(GUID, {
tabs: false,
toolbar: true,
worksheets: [
{
minDimensions: [4, 6],
worksheetName: "Sheet 1",
},
],
});
function stripImageButton(toolbarOptions) {
for (let i = 0; i < toolbarOptions.items.length; i++) {
if (toolbarOptions.items[i].content === "add_photo_alternate") {
toolbarOptions.items.splice(i, 1);
i--;
}
}
return toolbarOptions;
}
const commonOptions = {
guid: GUID,
toolbar: stripImageButton,
onbeforeloadimage: function () {
return "/templates/default/img/blocked.png";
},
};
const instA = jspreadsheet(sheetARef.current, commonOptions);
const instB = jspreadsheet(sheetBRef.current, commonOptions);
return () => {
try {
if (instA && typeof instA.destroy === "function") instA.destroy();
if (instB && typeof instB.destroy === "function") instB.destroy();
} catch (e) {
if (typeof jspreadsheet.destroyAll === "function") {
jspreadsheet.destroyAll();
}
}
};
}, []);
return (
<div>
<div
className="row middle"
style={{
justifyContent: "center",
maxWidth: `${maxParentWidth}px`,
margin: "0 auto",
}}
>
<div className="column p10">
<div
id="sheetA"
ref={sheetARef}
style={{
maxWidth: `${sheetMaxWidth}px`,
height: `${sheetHeight}px`,
boxSizing: "border-box",
}}
/>
</div>
<div className="column p10">
<div
id="sheetB"
ref={sheetBRef}
style={{
maxWidth: `${sheetMaxWidth}px`,
height: `${sheetHeight}px`,
boxSizing: "border-box",
}}
/>
</div>
</div>
<p style={{ textAlign: "center" }}>
Click here to find more information about the{" "}
<a href="/products/server">Jspreadsheet Server</a> extension
</p>
</div>
);
}
<template>
<div class="row middle" style="justify-content:center; max-width:1300px; margin:0 auto;">
<div class="column p10">
<Spreadsheet
ref="sheetA"
:license="license"
:guid="GUID"
:toolbar="stripImageButton"
:onbeforeloadimage="onBeforeLoadImage"
:tableOverflow="true"
:tableWidth="1300"
:tableHeight="500"
/>
</div>
<div class="column p10" style="margin-top:10px;">
<Spreadsheet
ref="sheetB"
:license="license"
:guid="GUID"
:toolbar="stripImageButton"
:onbeforeloadimage="onBeforeLoadImage"
:tableOverflow="true"
:tableWidth="1300"
:tableHeight="500"
/>
</div>
<p style="text-align:center; width:100%; margin-top:10px;">
Click here to find more information about the
<a href="/products/server">Jspreadsheet Server</a> extension
</p>
</div>
</template>
<script>
import { Spreadsheet, jspreadsheet } from "@jspreadsheet/vue";
import formula from '@jspreadsheet/formula-pro';
import client from '@jspreadsheet/client';
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('M2Q1MmFiODIzMTJjZjVhY2I5ZTBlMDA3MmJhNzQ0YzlhNDUwZjAyYjcwNjc2MTZlYWU3ZTAwOGJjNjQ1NTBlNTJlNjU2NzZjNjMxNjQ3MGRiMjkyZmFhYzFjZjVkOTY2MDg0MTExZThiZTU0NWRjZTU2MWVlZWM5MDdmZjMyNDIsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpreE56QTFPVGs0TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=');
jspreadsheet.setExtensions({ formula, client });
export default {
name: "JSServerMirrorVue",
components: { Spreadsheet },
data() {
return {
// Set your JSS license key (The following key only works for one day)
license: 'M2Q1MmFiODIzMTJjZjVhY2I5ZTBlMDA3MmJhNzQ0YzlhNDUwZjAyYjcwNjc2MTZlYWU3ZTAwOGJjNjQ1NTBlNTJlNjU2NzZjNjMxNjQ3MGRiMjkyZmFhYzFjZjVkOTY2MDg0MTExZThiZTU0NWRjZTU2MWVlZWM5MDdmZjMyNDIsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpreE56QTFPVGs0TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=',
GUID: "4b9e6f12-8c3a-4d57-b1e0-6a2f9c8d7e31",
SERVER_URL: "https://jspreadsheet.com",
SERVER_PATH: "s/",
};
},
created() {
const { jspreadsheet, formula, client } = window;
if (!jspreadsheet) {
console.error("jspreadsheet not found.");
return;
}
if (client && typeof client.connect === "function") {
const remote = client.connect({
url: this.SERVER_URL,
path: this.SERVER_PATH,
});
remote.create(this.GUID, {
tabs: false,
toolbar: true,
worksheets: [
{
minDimensions: [4, 6],
worksheetName: "Sheet 1",
},
],
});
}
},
methods: {
stripImageButton(toolbarOptions) {
if (!toolbarOptions || !Array.isArray(toolbarOptions.items)) return toolbarOptions;
for (let i = 0; i < toolbarOptions.items.length; i++) {
if (toolbarOptions.items[i].content === "add_photo_alternate") {
toolbarOptions.items.splice(i, 1);
i--;
}
}
return toolbarOptions;
},
onBeforeLoadImage() {
return "/templates/default/img/blocked.png";
},
},
beforeUnmount() {
const { jspreadsheet } = window;
if (jspreadsheet && typeof jspreadsheet.destroyAll === "function") {
jspreadsheet.destroyAll();
}
},
};
</script>
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Spreadsheet } from '@jspreadsheet/angular';
import { jspreadsheet } from 'jspreadsheet';
import formula from '@jspreadsheet/formula-pro';
import client from '@jspreadsheet/client';
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('M2Q1MmFiODIzMTJjZjVhY2I5ZTBlMDA3MmJhNzQ0YzlhNDUwZjAyYjcwNjc2MTZlYWU3ZTAwOGJjNjQ1NTBlNTJlNjU2NzZjNjMxNjQ3MGRiMjkyZmFhYzFjZjVkOTY2MDg0MTExZThiZTU0NWRjZTU2MWVlZWM5MDdmZjMyNDIsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpreE56QTFPVGs0TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=');
jspreadsheet.setExtensions({ formula, client });
declare global {
interface Window {
jspreadsheet: any;
formula: any;
client: any;
}
}
@Component({
selector: 'app-jss-server-mirror',
standalone: true,
imports: [Spreadsheet],
template: `
<div class="row middle"
style="justify-content:center; max-width:1300px; margin:0 auto;">
<div class="column p10">
<Spreadsheet
[license]="license"
[guid]="GUID"
[toolbar]="stripImageButton"
[onbeforeloadimage]="onBeforeLoadImage"
[tableOverflow]="true"
[tableWidth]="1300"
[tableHeight]="500">
</Spreadsheet>
</div>
<div class="column p10" style="margin-top:10px;">
<Spreadsheet
[license]="license"
[guid]="GUID"
[toolbar]="stripImageButton"
[onbeforeloadimage]="onBeforeLoadImage"
[tableOverflow]="true"
[tableWidth]="1300"
[tableHeight]="500">
</Spreadsheet>
</div>
<p style="text-align:center; width:100%; margin-top:10px;">
Click here to find more information about the
<a href="/products/server">Jspreadsheet Server</a> extension
</p>
</div>
`
})
export class JssServerMirrorComponent implements OnInit, OnDestroy {
// Set your JSS license key (The following key only works for one day)
license = 'M2Q1MmFiODIzMTJjZjVhY2I5ZTBlMDA3MmJhNzQ0YzlhNDUwZjAyYjcwNjc2MTZlYWU3ZTAwOGJjNjQ1NTBlNTJlNjU2NzZjNjMxNjQ3MGRiMjkyZmFhYzFjZjVkOTY2MDg0MTExZThiZTU0NWRjZTU2MWVlZWM5MDdmZjMyNDIsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpreE56QTFPVGs0TENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2liRzlqWVd4b2IzTjBJbDBzSW5Cc1lXNGlPaUl6TkNJc0luTmpiM0JsSWpwYkluWTNJaXdpZGpnaUxDSjJPU0lzSW5ZeE1DSXNJbll4TVNJc0luWXhNaUlzSW5ZeE15SXNJbU5vWVhKMGN5SXNJbVp2Y20xeklpd2labTl5YlhWc1lTSXNJbkJoY25ObGNpSXNJbkpsYm1SbGNpSXNJbU52YlcxbGJuUnpJaXdpYVcxd2IzSjBaWElpTENKaVlYSWlMQ0oyWVd4cFpHRjBhVzl1Y3lJc0luTmxZWEpqYUNJc0luQnlhVzUwSWl3aWMyaGxaWFJ6SWl3aVkyeHBaVzUwSWl3aWMyVnlkbVZ5SWl3aWMyaGhjR1Z6SWl3aVptOXliV0YwSWl3aWNHbDJiM1FpWFN3aVpHVnRieUk2ZEhKMVpYMD0=';
GUID = '4b9e6f12-8c3a-4d57-b1e0-6a2f9c8d7e31';
SERVER_URL = 'https://jspreadsheet.com';
SERVER_PATH = 's/';
ngOnInit(): void {
const { jspreadsheet, formula, client } = window;
if (!jspreadsheet) {
console.error('jspreadsheet not found.');
return;
}
if (typeof jspreadsheet.destroyAll === 'function') {
jspreadsheet.destroyAll();
}
if (client && typeof client.connect === 'function') {
const remote = client.connect({
url: this.SERVER_URL,
path: this.SERVER_PATH,
});
remote.create(this.GUID, {
tabs: false,
toolbar: true,
worksheets: [
{
minDimensions: [4, 6],
worksheetName: 'Sheet 1',
},
],
});
}
}
ngOnDestroy(): void {
const { jspreadsheet } = window;
if (jspreadsheet && typeof jspreadsheet.destroyAll === 'function') {
jspreadsheet.destroyAll();
}
}
stripImageButton = (toolbarOptions: any) => {
if (!toolbarOptions || !Array.isArray(toolbarOptions.items)) return toolbarOptions;
for (let i = 0; i < toolbarOptions.items.length; i++) {
if (toolbarOptions.items[i].content === 'add_photo_alternate') {
toolbarOptions.items.splice(i, 1);
i--;
}
}
return toolbarOptions;
};
onBeforeLoadImage = () => {
return '/templates/default/img/blocked.png';
};
}
How it works
client.connect({ url, path })opens one realtime connection to Jspreadsheet Server.remote.create(guid, config)creates the document the first time; afterwards it already exists and the call does nothing.- Every spreadsheet created with the same
guidloads that document from the server and stays in sync with it: edits, formulas, styles and worksheets. - The server persists each change through your adapter and authorizes every request through your hooks. See Jspreadsheet Server.
For a complete application built on the same server, see the Intrasheets demo.