# 스프레드시트 변경 사항 저장

## Content

SpreadJS는 스프레드시트의 수정 내용을 저장할 수 있습니다. 아래 섹션에서는 필요한 단계별 과정을 설명합니다.

## 스프레드시트 변경 사항 저장 및 새로 고침

다음 섹션에서는 스프레드시트에서 이루어진 변경 사항을 저장하고, 스프레드시트를 새로 고침하여 모든 변경 사항을 제거하는 단계를 설명합니다.

### Step 1: 스프레드시트 수정 및 보호

1. [데이터 원본 바인딩](/spreadjs/docs/getstarted/quick-start/binding-to-datasource) 섹션에서 생성한 **refresh** 함수를 수정합니다. **loadTable** 함수를 호출한 후, **suspendDirty** 및 **resumeDirty** 메서드를 실행하여 F 열에서 이루어진 변경 사항이 저장되지 않도록 합니다.
2. 스프레드시트의 F1 셀에 값, 배경색, 수평 정렬을 설정합니다.
3. 스프레드시트를 보호하기 위해 **isProtected** 옵션을 true로 설정합니다.
4. 스프레드시트의 셀이 잠기지 않도록 **locked** 메서드를 false로 설정합니다.

    ```javascript
    //1: 값, 배경색, halign을 suspendDirty / resumeDirty 사이에 설정 & 시트 보호 및 F 열 잠금
    function refresh() {
        var ss = GC.Spread.Sheets.findControl(document.getElementById("ss"));
        // 활성 시트 가져오기
        var sheet = ss.getActiveSheet();
        // 시트를 초기화하고 열 개수 설정
        sheet.reset();
        sheet.setColumnCount(7);
        // 샘플 데이터를 사용하여 Spread 인스턴스에 테이블 로드
        var data = createSampleData();
        loadTable(ss, data);
        // suspendDirty / resumeDirty 사이에서 값, 배경색, halign 설정
        // dirty 셀 중지
        sheet.suspendDirty();
        // F1 셀의 값, 배경색, halign 설정
        sheet
            .getCell(0, 5)
            .backColor("yellow")
            .value("Changes")
            .hAlign(GC.Spread.Sheets.HorizontalAlign.center);
        // dirty 셀 재개
        sheet.resumeDirty();
    
        // 시트 보호 및 F 열 잠금
        sheet.options.isProtected = true;
        // 4.1) 기본 스타일을 설정하여 셀 잠금 해제
        var s = sheet.getDefaultStyle();
        s.locked = false;
        sheet.setDefaultStyle(s);
        // 4.2) 열 F를 잠금 처리하여 새 값과 이전 값을 표시 (열 인덱스 5)
        sheet.getRange(-1, 5, -1, 1).locked(true);
    ```
5. `refresh` 함수를 실행하는 'Refresh' HTML 입력 버튼을 생성합니다.

    ```javascript
    <!--Refresh 버튼 생성-->
    <input type="button" value="Refresh" onclick="refresh()" />
    ```

### Step 2: Dirty 셀 정보 가져오기

1. **showChanges** 함수를 생성하고, **getDirtyCells** 및 **hasPendingChanges** 메서드를 사용하여 dirty 셀과 보류 중인 변경 사항 정보를 가져옵니다.
2. 행, 열, rowCount, colCount 정보를 포함한 dirty 셀 정보를 저장하기 위해 **dirtyDataArray**라는 데이터 배열을 생성합니다.
3. **setValue** 메서드를 사용하여 F 열의 셀에 dirty 셀의 이전 값과 새로운 값을 표시합니다.

    ```javascript
    // Step 2: showChanges() 생성
    function showChanges(ss, row, col, rowCount, colCount) {
        // 활성 시트 가져오기
        var sheet = ss.getActiveSheet();
        // 활성 시트에 보류 중인 변경 사항이 있는 경우
        if (sheet.hasPendingChanges()) {
            // Paint, Event, Dirty 중지
            ss.suspendPaint();
            ss.suspendEvent();
            sheet.suspendDirty();
            // dirty 셀 컬렉션을 dirtyDataArray 배열에 저장
            var dirtyDataArray = sheet.getDirtyCells(row, col, rowCount, colCount);
    
            // F 열의 dirty 변경 사항 건너뛰기
            for (var i = 0; i < dirtyDataArray.length; i++) {
                // dirty 셀 데이터를 dirtyDataArray에 저장
                var dirtyCell = dirtyDataArray[i];
    
                // dirtyDataArray 값에서 이전 값과 새 값 표시
                // row index --> dirtyCell.row는 변경된 행의 인덱스를 반환
                // column index --> 5는 F 열의 인덱스
                sheet.setValue(
                    dirtyCell.row,
                    5,
                    "old: " + dirtyCell.oldValue + ", new: " + dirtyCell.newValue
                );
            }
            // Dirty, Event, Paint 재개
            sheet.resumeDirty();
            ss.resumeEvent();
            ss.resumePaint();
        }
    }
    ```

### Step 3: Dirty 셀 값 표시

스프레드시트가 수정될 때마다 **showChange** 함수를 실행하도록 활성 시트에 **CellChanged** 및 **RangeChanged** 이벤트를 바인딩합니다.

```auto
// Step 3: CellChanged 및 RangeChanged 이벤트를 시트에 바인딩
$(document).ready(function () {
    // Spread 초기화
    var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"));
    // refresh 함수 호출
    refresh();
    // CellChanged 바인딩
    spread.bind(GC.Spread.Sheets.Events.CellChanged, function (event, data) {
        var row = data.row,
            col = data.col;
        if (
            data.propertyName !== "value" ||
            row === undefined ||
            col === undefined
        ) {
            return;
        }
        // showChanged 함수 실행
        showChanges(spread, row, col);
    });
    // RangeChanged 바인딩
    spread.bind(GC.Spread.Sheets.Events.RangeChanged, function (event, data) {
        var row = data.row,
            col = data.col,
            rowCount = data.rowCount,
            colCount = data.colCount;
        if (
            row === undefined ||
            col === undefined ||
            rowCount === undefined ||
            colCount === undefined
        ) {
            return;
        }
        // showChanged 함수 실행
        showChanges(spread, row, col, rowCount, colCount);
    });
});
```

이전 값과 새로운 값은 F 열에 표시됩니다. 또한 F 열은 잠겨 있어 그 내용을 수정할 수 없습니다. **Refresh** 버튼을 사용하여 Spread 인스턴스를 새로 고쳐 모든 변경 사항을 제거할 수도 있습니다. 위 코드의 출력은 아래와 같이 표시됩니다:
![capture_ refresh_spreadsheet_changes.c5ef34.png](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/216c2e7e-5246-4c37-8843-3854aa344a6a/capture_%20refresh_spreadsheet_changes.c5ef34.f77e78.png?width=820)

## 스프레드시트 변경 사항을 데이터베이스에 저장

다음 섹션에서는 스프레드시트 변경 사항을 데이터베이스에 저장하는 단계를 설명합니다.

> **참고:** SpreadJS는 데이터베이스를 직접 업데이트하지 않습니다. 하지만 변경된 데이터를 다음 방법으로 가져와 데이터베이스를 업데이트할 수 있습니다.

### Step 1: Dirty 셀 정보 가져오기 및 JSON 문자열로 변환

1. **saveToDB** 함수를 생성하고, **getDirtyCells** 메서드를 사용하여 dirty 셀(변경된 셀)의 정보를 가져옵니다.
2. **JSON.stringify** 메서드를 사용하여 dirty 셀 정보를 JSON 문자열로 변환합니다.

    ```javascript
    //1: saveToDB() 생성
    function saveToDB() {
        // DOM 요소 "ss"에서 활성 시트 가져오기
        var ss = GC.Spread.Sheets.findControl(document.getElementById("ss"));
        var sheet = ss.getActiveSheet();
        // dirty 셀 정보를 dirtyCells 변수에 저장
        var dirtyCells = sheet.getDirtyCells();
        // Step 2에서 생성할 HTML <div> 요소 "msg" 가져오기
        var div = document.getElementById("msg");
        // 변경된 셀 정보를 JSON 문자열로 변환하여 div 요소에 표시
        div.innerHTML = JSON.stringify(dirtyCells, null, 4);
        // 참고: 데이터베이스에 변경 사항 전송
    }
    ```

### Step 2: 데이터베이스에 변경 사항 저장

1. SpreadJS `<div>` 요소 뒤에 **msg** ID를 가진 HTML `<div>` 요소를 생성하여 JSON 문자열을 표시합니다.
2. **saveToDB** 함수가 호출되는 **Save to DB** 입력 버튼을 생성합니다. Save to DB 버튼을 클릭하면 캡처된 변경 사항이 JSON 문자열로 변환되어 **msg** ID `<div>`에 표시됩니다.

    ```auto
    <body>
        <h1>스프레드시트의 변경 사항을 데이터베이스에 저장</h1>
        <p>
            이 섹션에서는 Save to DB 버튼과 DIV를 생성하여, Save to DB 버튼을 클릭할 때 변경 사항을 JSON 문자열로 표시합니다.
        </p>
        <!-- Refresh 버튼 생성 -->
        <input type="button" value="Refresh" onclick="refresh()" />
        <!-- Save to DB <div> 및 버튼 생성 -->
        <input type="button" value="Save to DB" onclick="saveToDB()" />
        <br />
        <br />
        <div id="ss" style="height:400px;width:900px"></div>
        <!-- 변경 사항 <div> -->
        <div class="options-container">
            <h4> 데이터베이스에 저장된 변경 사항: </h4>
            <div id="msg" style="width: 100%; height: 260px; border: 1px solid grey;"></div>
        </div>
    </body>
    ```

데이터베이스에 게시될 변경 사항이 포함된 JSON 문자열은 출력에 다음과 같이 표시됩니다:
![](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/8d606653-16a0-474d-b9dc-e2b4d01c2446/images/save-changes-to-database.PNG?width=800)