요청 처리

테이블 시트는 원격 요청 옵션을 구성하기 위한 자체 정의 함수를 지원합니다.

기본적으로 테이블 시트는 개체의 원격 요청을 구성합니다. 요청을 수동으로 처리하려는 경우 함수의 개체를 바꾸면 데이터 변경 사항이 함수에 전달됩니다. 데이터 변경 세부 정보는 개요의 요청 및 응답 섹션에 있습니다. AutoSync 모드 AutoSync 모드의 요청 처리: Batch 모드 Batch 모드의 요청 처리: 데이터 소스 옵션 변경 표에서 CRUD 옵션 대신 CRUD 함수를 사용하는 경우 이러한 함수는 보안 문제 때문에 JSON 직렬화/역직렬화 후 저장 및 복원할 수 없습니다. fromJSON 메서드를 호출한 후 표의 데이터 소스 옵션을 설정하면 테이블이 다시 작동할 수 있습니다. 데이터 다시 로드 표의 fetch 메서드가 호출되고 이 메서드의 reload 인수가 true이면 표가 데이터를 다시 로드합니다. 보기의 fetch 메서드는 표의 fetch 메서드와 reload 인수가 동일합니다.
/*REPLACE_MARKER*/ /*DO NOT DELETE THESE COMMENTS*/ import { Component, NgModule, enableProdMode } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { SpreadSheetsModule } from '@mescius/spread-sheets-angular'; import GC from '@mescius/spread-sheets'; import "@mescius/spread-sheets-tablesheet"; import '@mescius/spread-sheets-resources-ko'; GC.Spread.Common.CultureManager.culture("ko-kr"); import './styles.css'; var tableName = "Employee"; var baseApiUrl = getBaseApiUrl(); var apiUrl = baseApiUrl + "/" + tableName; var batchApiUrl = baseApiUrl + "/" + tableName + 'Collection'; var tablesheetName = 'MyTableSheet'; function sendRequest(url: string, options: any) { 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; } }); } @Component({ selector: 'app-component', templateUrl: 'src/app.component.html' }) export class AppComponent { methods4html = { objectKeys: Object.keys, number: Number }; spread: GC.Spread.Sheets.Workbook; tablesheet: GC.Spread.Sheets.TableSheet; fields = {}; selections; isEdit = false; hostStyle = { width: "calc(100% - 280px)", height: "100%", overflow: "hidden", float: "left" }; constructor() { } initSpread($event: any) { let spread = $event.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' }); }, batch: function (changes: any[]) { 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); 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\/learn-spreadjs\//)[0] + 'server/api'; } @NgModule({ imports: [BrowserModule, SpreadSheetsModule, FormsModule], declarations: [AppComponent], exports: [AppComponent], bootstrap: [AppComponent] }) export class AppModule { } enableProdMode(); // Bootstrap application with hash style navigation and global services. platformBrowserDynamic().bootstrapModule(AppModule);
<!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$/ko/angular/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <!-- Polyfills --> <script src="$DEMOROOT$/ko/angular/node_modules/core-js/client/shim.min.js"></script> <script src="$DEMOROOT$/ko/angular/node_modules/zone.js/fesm2015/zone.min.js"></script> <!-- SystemJS --> <script src="$DEMOROOT$/ko/angular/node_modules/systemjs/dist/system.js"></script> <script src="systemjs.config.js"></script> <script> // workaround to load 'rxjs/operators' from the rxjs bundle System.import('rxjs').then(function (m) { System.import('@angular/compiler'); System.set(SystemJS.resolveSync('rxjs/operators'), System.newModule(m.operators)); System.import('$DEMOROOT$/ko/lib/angular/license.ts'); System.import('./src/app.component'); }); </script> </head> <body> <app-component></app-component> </body> </html>
<div class="sample-tutorial"> <gc-spread-sheets [hostStyle]="hostStyle" (workbookInitialized)="initSpread($event)"></gc-spread-sheets> <div id="options-container" class="options-container"> <fieldset> <legend>Active Row Operations</legend> <div class="field-line"> <input id="remove" type="button" value="Remove" (click)="removeRow()"> </div> <div class="field-line"> <input id="save" type="button" value="Save" (click)="saveRow()"> </div> <div class="field-line"> <input id="reset" type="button" value="Reset" (click)="resetRow()"> </div> </fieldset> <fieldset> <legend>Save All Rows</legend> <div class="field-line"> <input id="save-all" type="button" value="Save All" (click)="saveAllRows()"> </div> </fieldset> <fieldset> <legend>Batch Operations</legend> <div class="field-line"> <input type="button" value="Submit" id="submit" (click)="submitChanges()"> </div> <div class="field-line"> <input type="button" value="Discard" id="discard" (click)="discardChanges()"> </div> </fieldset> </div> </div>
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: 'ts', typescriptOptions: { tsconfig: true }, meta: { 'typescript': { "exports": "ts" }, '*.css': { loader: 'css' } }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { 'core-js': 'npm:core-js/client/shim.min.js', 'zone': 'npm:zone.js/fesm2015/zone.min.js', 'rxjs': 'npm:rxjs/dist/bundles/rxjs.umd.min.js', '@angular/core': 'npm:@angular/core/fesm2022', '@angular/common': 'npm:@angular/common/fesm2022/common.mjs', '@angular/compiler': 'npm:@angular/compiler/fesm2022/compiler.mjs', '@angular/platform-browser': 'npm:@angular/platform-browser/fesm2022/platform-browser.mjs', '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/fesm2022/platform-browser-dynamic.mjs', '@angular/common/http': 'npm:@angular/common/fesm2022/http.mjs', '@angular/router': 'npm:@angular/router/fesm2022/router.mjs', '@angular/forms': 'npm:@angular/forms/fesm2022/forms.mjs', 'jszip': 'npm:jszip/dist/jszip.min.js', 'typescript': 'npm:typescript/lib/typescript.js', 'ts': './plugin.js', 'tslib':'npm:tslib/tslib.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', '@mescius/spread-sheets': 'npm:@mescius/spread-sheets/index.js', '@mescius/spread-sheets-tablesheet': 'npm:@mescius/spread-sheets-tablesheet/index.js', '@mescius/spread-sheets-resources-ko': 'npm:@mescius/spread-sheets-resources-ko/index.js', '@mescius/spread-sheets-angular': 'npm:@mescius/spread-sheets-angular/fesm2020/mescius-spread-sheets-angular.mjs', '@grapecity/jsob-test-dependency-package/react-components': 'npm:@grapecity/jsob-test-dependency-package/react-components/index.js' }, // packages tells the System loader how to load when no filename and/or no extension packages: { src: { defaultExtension: 'ts' }, rxjs: { defaultExtension: 'js' }, "node_modules": { defaultExtension: 'js' }, "node_modules/@angular": { defaultExtension: 'mjs' }, "@mescius/spread-sheets-angular": { defaultExtension: 'mjs' }, '@angular/core': { defaultExtension: 'mjs', main: 'core.mjs' } } }); })(this);