By default, the TableSheet will configure the remote requests by an object. If you want to handle the request manually, just replace the object of the function, and the data and column changes will be passed to the function.
The details of the data changes are in the Request and Response section of the Overview.
AutoSync Mode
Handle requests in the AutoSync mode:
Batch Mode
Handle requests in the Batch mode:
Change data source options
When a Table uses CRUD functions instead of CRUD options, these functions can't be saved and restored after JSON serialization / deserialization because of security issue.
Setting the Table’s data source options after the fromJSON method is invoked could make the Table working again.
Reload data
When a Table’s fetch method is invoked and its reload argument is true, the Table will load data again.
And a View’s fetch method has same reload argument with a Table’s fetch method.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import './styles.css';
import { AppFunc } from './app-func';
import { App } from './app-class';
// 1. Functional Component sample
ReactDOM.render(<AppFunc />, document.getElementById('app'));
// 2. Class Component sample
// ReactDOM.render(<App />, document.getElementById('app'));
/*REPLACE_MARKER*/
/*DO NOT DELETE THESE COMMENTS*/
import * as React from 'react';
import GC from '@mescius/spread-sheets';
import "@mescius/spread-sheets-tablesheet";
import { SpreadSheets } from '@mescius/spread-sheets-react';
import './styles.css';
var tableName = "DefineEmployee";
var baseApiUrl = getBaseApiUrl();
var apiUrl = baseApiUrl + "/" + tableName;
// var apiColumnUrl = baseApiUrl + "/tables/" + tableName + "/columns";
var batchApiUrl = baseApiUrl + "/" + tableName + 'Collection';
var tablesheetName = 'MyTableSheet';
function sendRequest(url, options) {
options.method = options.method || 'POST';
options.headers = { 'Content-Type': 'application/json; charset=utf-8' };
if (options.body) {
options.body = JSON.stringify(options.body);
}
return fetch(url, options).then(resp => {
if (resp.ok) {
return resp.json();
} else {
throw resp.statusText;
}
});
}
const useState = React.useState;
let spread = null;
export function AppFunc() {
const [tablesheet, setTablesheet] = useState(null);
const [selections, setSelections] = useState(null);
const initSpread = (currSpread) => {
spread = currSpread;
spread.suspendPaint();
spread.clearSheets();
spread.options.autoFitType = GC.Spread.Sheets.AutoFitType.cellWithHeader;
//init a data manager
var dataManager = spread.dataManager();
var myTable = dataManager.addTable("myTable", {
remote: {
read: function () {
return sendRequest(apiUrl, { method: 'GET' });
},
// update: function (item) {
// return sendRequest(apiUrl, { body: item, method: 'PUT' });
// },
// create: function (item) {
// return sendRequest(apiUrl, { body: item });
// },
// delete: function (item) {
// return sendRequest(apiUrl, { body: item, method: 'DELETE' });
// },
// getColumns: function () {
// return sendRequest(apiColumnUrl, { method: 'GET' });
// },
// updateColumn: function (change) {
// return sendRequest(apiColumnUrl, { body: change, method: 'PUT' });
// },
// addColumn: function (change) {
// return sendRequest(apiColumnUrl, { body: change });
// },
// removeColumn: function (change) {
// return sendRequest(apiColumnUrl, { body: change, method: 'DELETE' });
// },
batch: function (changes) {
return sendRequest(batchApiUrl, { body: changes });
}
},
batch: true,
schema: {
columns: {
"Id": { dataType: "number" },
"LastName": { dataType: "string" },
"FirstName": { dataType: "string" },
"HomePhone": { dataType: "string" },
"Notes": { dataType: "string" }
}
}
});
//init a table sheet
var sheet = spread.addSheetTab(0, tablesheetName, GC.Spread.Sheets.SheetType.tableSheet);
// sheet.options.enableDefineColumn = true;
setTablesheet(sheet);
var rowActions = GC.Spread.Sheets.TableSheet.BuiltInRowActions;
var options = sheet.rowActionOptions();
options.push(
rowActions.removeRow,
rowActions.saveRow,
rowActions.resetRow,
);
sheet.rowActionOptions(options);
//bind a view to the table sheet
myTable.fetch().then(function () {
var view = myTable.addView("myView", [
{ value: "Id", width: 50, caption: "ID" },
{ value: "FirstName", width: 100, caption: "First Name" },
{ value: "LastName", width: 100, caption: "Last Name" },
{ value: "HomePhone", width: 100, caption: "Phone" },
{ value: "Notes", width: 100, caption: "Notes" }
]); //the View has all default columns of the Table
sheet.setDataView(view);
});
spread.bind(GC.Spread.Sheets.Events.SelectionChanged, (e, args) => {
setSelections(args.newSelections);
});
spread.resumePaint();
}
const removeRow = () => {
traverseSelectionsRowsWithOperation((row) => {
tablesheet.removeRow(row);
});
}
const saveRow = () => {
traverseSelectionsRowsWithOperation((row) => {
tablesheet.saveRow(row);
});
}
const resetRow = () => {
traverseSelectionsRowsWithOperation((row) => {
tablesheet.resetRow(row);
});
}
const saveAllRows = () => {
spread.commandManager().SaveAll.execute(spread, { sheetName: tablesheetName });
}
const submitChanges = () => {
tablesheet.submitChanges();
}
const discardChanges = () => {
tablesheet.cancelChanges();
}
const traverseSelectionsRowsWithOperation = (operation) => {
if (selections) {
for (var i = 0; i < selections.length; i++) {
var selection = selections[i];
var row = selection.row;
var rowCount = selection.rowCount;
for (var r = row + rowCount - 1; r >= row; r--) {
operation(r);
}
}
}
}
return (
<div class="sample-tutorial">
<div class="sample-spreadsheets">
<SpreadSheets workbookInitialized={spread => initSpread(spread)}></SpreadSheets>
</div>
<div id="options-container" class="options-container">
<fieldset>
<legend>Active Row Operations</legend>
<div class="field-line">
<input id="remove" type="button" value="Remove" onClick={() => { removeRow() }} />
</div>
<div class="field-line">
<input id="save" type="button" value="Save" onClick={() => { saveRow() }} />
</div>
<div class="field-line">
<input id="reset" type="button" value="Reset" onClick={() => { resetRow() }} />
</div>
</fieldset>
<fieldset>
<legend>Save All Rows</legend>
<div class="field-line">
<input id="save-all" type="button" value="Save All" onClick={() => { saveAllRows() }} />
</div>
</fieldset>
<fieldset>
<legend>Batch Operations</legend>
<div class="field-line">
<input type="button" value="Submit" id="submit" onClick={() => { submitChanges() }} />
</div>
<div class="field-line">
<input type="button" value="Discard" id="discard" onClick={() => { discardChanges() }} />
</div>
</fieldset>
</div>
</div>
);
}
function getBaseApiUrl() {
return window.location.href.match(/http.+spreadjs\/demos\//)[0] + 'server/api';
}
/*REPLACE_MARKER*/
/*DO NOT DELETE THESE COMMENTS*/
import * as React from 'react';
import GC from '@mescius/spread-sheets';
import "@mescius/spread-sheets-tablesheet";
import { SpreadSheets } from '@mescius/spread-sheets-react';
import './styles.css';
const Component = React.Component;
var tableName = "DefineEmployee";
var baseApiUrl = getBaseApiUrl();
var apiUrl = baseApiUrl + "/" + tableName;
// var apiColumnUrl = baseApiUrl + "/tables/" + tableName + "/columns";
var batchApiUrl = baseApiUrl + "/" + tableName + 'Collection';
var tablesheetName = 'MyTableSheet';
function sendRequest(url, options) {
options.method = options.method || 'POST';
options.headers = { 'Content-Type': 'application/json; charset=utf-8' };
if (options.body) {
options.body = JSON.stringify(options.body);
}
return fetch(url, options).then(resp => {
if (resp.ok) {
return resp.json();
} else {
throw resp.statusText;
}
});
}
export class App extends Component {
constructor(props) {
super(props);
this.spread = null;
this.tablesheet = null;
this.selections = null;
}
render() {
return (
<div class="sample-tutorial">
<div class="sample-spreadsheets">
<SpreadSheets workbookInitialized={spread => this.initSpread(spread)}></SpreadSheets>
</div>
<div id="options-container" class="options-container">
<fieldset>
<legend>Active Row Operations</legend>
<div class="field-line">
<input id="remove" type="button" value="Remove" onClick={() => { this.removeRow() }} />
</div>
<div class="field-line">
<input id="save" type="button" value="Save" onClick={() => { this.saveRow() }} />
</div>
<div class="field-line">
<input id="reset" type="button" value="Reset" onClick={() => { this.resetRow() }} />
</div>
</fieldset>
<fieldset>
<legend>Save All Rows</legend>
<div class="field-line">
<input id="save-all" type="button" value="Save All" onClick={() => { this.saveAllRows() }} />
</div>
</fieldset>
<fieldset>
<legend>Batch Operations</legend>
<div class="field-line">
<input type="button" value="Submit" id="submit" onClick={() => { this.submitChanges() }} />
</div>
<div class="field-line">
<input type="button" value="Discard" id="discard" onClick={() => { this.discardChanges() }} />
</div>
</fieldset>
</div>
</div>
);
}
initSpread(spread) {
this.spread = spread;
spread.suspendPaint();
spread.clearSheets();
spread.options.autoFitType = GC.Spread.Sheets.AutoFitType.cellWithHeader;
//init a data manager
var dataManager = spread.dataManager();
var myTable = dataManager.addTable("myTable", {
remote: {
read: function () {
return sendRequest(apiUrl, { method: 'GET' });
},
// update: function (item) {
// return sendRequest(apiUrl, { body: item, method: 'PUT' });
// },
// create: function (item) {
// return sendRequest(apiUrl, { body: item });
// },
// delete: function (item) {
// return sendRequest(apiUrl, { body: item, method: 'DELETE' });
// },
// getColumns: function () {
// return sendRequest(apiColumnUrl, { method: 'GET' });
// },
// updateColumn: function (change) {
// return sendRequest(apiColumnUrl, { body: change, method: 'PUT' });
// },
// addColumn: function (change) {
// return sendRequest(apiColumnUrl, { body: change });
// },
// removeColumn: function (change) {
// return sendRequest(apiColumnUrl, { body: change, method: 'DELETE' });
// },
batch: function (changes) {
return sendRequest(batchApiUrl, { body: changes });
}
},
batch: true,
schema: {
columns: {
"Id": { dataType: "number" },
"LastName": { dataType: "string" },
"FirstName": { dataType: "string" },
"HomePhone": { dataType: "string" },
"Notes": { dataType: "string" }
}
}
});
//init a table sheet
var sheet = spread.addSheetTab(0, tablesheetName, GC.Spread.Sheets.SheetType.tableSheet);
// sheet.options.enableDefineColumn = true;
this.tablesheet = sheet;
var rowActions = GC.Spread.Sheets.TableSheet.BuiltInRowActions;
var options = sheet.rowActionOptions();
options.push(
rowActions.removeRow,
rowActions.saveRow,
rowActions.resetRow,
);
sheet.rowActionOptions(options);
//bind a view to the table sheet
myTable.fetch().then(function () {
var view = myTable.addView("myView", [
{ value: "Id", width: 50, caption: "ID" },
{ value: "FirstName", width: 100, caption: "First Name" },
{ value: "LastName", width: 100, caption: "Last Name" },
{ value: "HomePhone", width: 100, caption: "Phone" },
{ value: "Notes", width: 100, caption: "Notes" }
]); //the View has all default columns of the Table
sheet.setDataView(view);
});
spread.bind(GC.Spread.Sheets.Events.SelectionChanged, (e, args) => {
this.selections = args.newSelections;
});
spread.resumePaint();
}
removeRow() {
this.traverseSelectionsRowsWithOperation((row) => {
this.tablesheet.removeRow(row);
});
}
saveRow() {
this.traverseSelectionsRowsWithOperation((row) => {
this.tablesheet.saveRow(row);
});
}
resetRow() {
this.traverseSelectionsRowsWithOperation((row) => {
this.tablesheet.resetRow(row);
});
}
saveAllRows() {
this.spread.commandManager().SaveAll.execute(this.spread, { sheetName: tablesheetName });
}
submitChanges() {
this.tablesheet.submitChanges();
}
discardChanges() {
this.tablesheet.cancelChanges();
}
traverseSelectionsRowsWithOperation(operation) {
var selections = this.selections;
if (selections) {
for (var i = 0; i < selections.length; i++) {
var selection = selections[i];
var row = selection.row;
var rowCount = selection.rowCount;
for (var r = row + rowCount - 1; r >= row; r--) {
operation(r);
}
}
}
}
}
function getBaseApiUrl() {
return window.location.href.match(/http.+spreadjs\/demos\//)[0] + 'server/api';
}
<!doctype html>
<html style="height:100%;font-size:14px;">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/react/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css">
<!-- SystemJS -->
<script src="$DEMOROOT$/en/react/node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('$DEMOROOT$/en/lib/react/license.js').then(function () {
System.import('./src/app');
});
</script>
</head>
<body>
<div id="app" style="height: 100%;"></div>
</body>
</html>
body {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
fieldset {
padding: 6px;
margin: 0;
margin-top: 10px;
}
.sample-tutorial {
position: relative;
height: 100%;
overflow: hidden;
}
.sample-spreadsheets {
width: calc(100% - 280px);
height: 100%;
overflow: hidden;
float: left;
}
.options-container {
float: right;
width: 280px;
padding: 12px;
height: 100%;
box-sizing: border-box;
background: #fbfbfb;
overflow: auto;
}
fieldset span,
fieldset input,
fieldset select {
display: inline-block;
text-align: left;
}
fieldset input[type=text] {
width: calc(100% - 58px);
}
fieldset input[type=button] {
width: 100%;
text-align: center;
}
fieldset select {
width: calc(100% - 50px);
}
.field-line {
margin-top: 4px;
}
.field-inline {
display: inline-block;
vertical-align: middle;
}
fieldset label.field-inline {
width: 100px;
}
fieldset input.field-inline {
width: calc(100% - 100px - 12px);
}
.required {
color: red;
font-weight: bold;
}
#fields {
display: none;
}
#fields.show {
display: block;
}
(function (global) {
System.config({
transpiler: 'plugin-babel',
babelOptions: {
es2015: true,
react: true
},
meta: {
'*.css': { loader: 'css' }
},
paths: {
// paths serve as alias
'npm:': 'node_modules/'
},
// map tells the System loader where to look for things
map: {
'@mescius/spread-sheets': 'npm:@mescius/spread-sheets/index.js',
'@mescius/spread-sheets-tablesheet': 'npm:@mescius/spread-sheets-tablesheet/index.js',
'@mescius/spread-sheets-react': 'npm:@mescius/spread-sheets-react/index.js',
'@grapecity/jsob-test-dependency-package/react-components': 'npm:@grapecity/jsob-test-dependency-package/react-components/index.js',
'react': 'npm:react/umd/react.production.min.js',
'react-dom': 'npm:react-dom/umd/react-dom.production.min.js',
'css': 'npm:systemjs-plugin-css/css.js',
'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js',
'systemjs-babel-build':'npm:systemjs-plugin-babel/systemjs-babel-browser.js'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
src: {
defaultExtension: 'jsx'
},
"node_modules": {
defaultExtension: 'js'
},
}
});
})(this);