Jspreadsheet 使い方メモ４-2（メソッド）

# はじめに
これは、[Jspreadsheet Advent Calendar 2024](https://qiita.com/advent-calendar/2024/jspreadsheet)の23日目の記事となります。

「[Handsontable 使い方メモ４（メソッド）](https://qiita.com/opengl-8080/items/e756af444147771fab18)」と比較しながら書いていきます。

※全てのメソッドは網羅していません。

全てのメソッドを確認したい場合は、 [公式ドキュメント](https://bossanova.uk/jspreadsheet/v4/docs/quick-reference) を参照

メソッドの記事は長かったため、分割することにしました。

## 注意
現時点(2025/03/09)では、Jspreadsheet CE Version 4 を対象としています。
Version 5 のリリースにより見直す予定です。

https://bossanova.uk/jspreadsheet/docs/upgrade-from-v4-to-v5

# メソッド
## データを取得する
### セルを指定してデータを取得する
Handsontableの`getDataAtCell`の機能に近いものは、`getValue`にあたる。

```js
let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  data: [
    [1, 2, 3],
    [true, false, true],
    ['hoge', 'fuga', 'piyo']
  ]
});

console.log(table.getValue('A1'));
console.log(table.getValue('B2'));
console.log(table.getValue('C3'));
```

```text:実行結果
1
false
piyo
```

* セル名(A1形式)を指定して値を取得する

セルのインデックスを指定して値を取得するには別途関数を作成する必要がある

```js
table.getDataAtCell = function(x, y) {
  let cellName = jspreadsheet.getColumnNameFromId([x,y]);
  return this.getValue(cellName);
}

console.log(table.getDataAtCell(0,0));
console.log(table.getDataAtCell(1,1));
console.log(table.getDataAtCell(2,2));
```

### 指定した列のデータを全て取得する
Handsontableの`getDataAtCol`がないため、別途関数を作成する必要がある。

```js
table.getDataAtCol = function(col) {
  return this.getData().map((_, row) => this.getDataAtCell(col, row));
}

console.log(table.getDataAtCol(1));
```

```text:実行結果
[2, false, 'fuga']
```

* 列のインデックスを指定して、その列の全ての値を配列で取得する

### 指定した行のデータを全て取得する
Handsontableの`getDataAtRow`がないため、別途関数を作成する必要がある。

```js
table.getDataAtRow = function(row) {
  return table.getData()[0].map((_, col) => this.getDataAtCell(col, row));
}

console.log(table.getDataAtRow(2));
```

```text:実行結果
['hoge', 'fuga', 'piyo']
```

* 行のインデックスを指定して、その行の全ての値を配列で取得する

### 指定した列名のデータを全て取得する
Handsontableの`getDataAtProp`がないため、別途関数を作成する必要がある。

```js
let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  data: [
    { name: 'sato',   age: 13 },
    { name: 'suzuki', age: 15 },
    { name: 'tanaka', age: 18 }
  ]
});

table.getDataAtProp = function(prop) {
  return this.getData().map(row => row[prop]);
}

//console.log(table.getDataAtProp('name'));
console.log(table.getDataAtProp(0))
```

```text:実行結果
['sato', 'suzuki', 'tanaka']
```

* ~~列名~~ 列のインデックスを指定して、その列の全てのデータを配列で取得する

※Jspreadsheet CEでは、table.getData() のデータ構造が [[], [], []] のように 配列の配列 になっており、オブジェクトの配列ではありません。

### 行インデックスと列名を指定してデータを取得する
Handsontableの`getDataAtRowProp`がないため、別途関数を作成する必要がある。

```js
table.getDataAtRowProp = function(row, prop) {
  return this.getData()[row]?.[prop] ?? null; 
}

//console.log(table.getDataAtRowProp(0, 'age'));
console.log(table.getDataAtRowProp(0, 1));
```

```text:実行結果
13
```

* 行のインデックスと~~列名~~ 列のインデックスを指定して、そのセルのデータを取得する

※Jspreadsheet CEでは、table.getData() のデータ構造が [[], [], []] のように 配列の配列 になっており、オブジェクトの配列ではありません。

### データをまるごと取得する
Handsontableの`getData`と同じ機能である。

```js
let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  data: [
    { name: 'sato',   age: 13 },
    { name: 'suzuki', age: 15 },
    { name: 'tanaka', age: 18 }
  ]
});
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/bef6d399-8ffc-483d-b3e9-94aa9b0259b3.png)

* 引数無しの場合、全てのデータを取得する
* 引数有り(bool)の場合、trueでハイライトされたデータを取得する

※Handsontableと違い、範囲指定によるデータ取得は出来ない。

## ソースデータをそのまま取得する
Handsontableの`getSourceData`のような機能はない。

## セルのデータ型を取得する
Handsontableの`getDataType`がないため、別途関数を作成する必要がある。

```js
let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  minDimensions: [4,3],
  columns: [
    { type: 'text' },
    { type: 'numeric' },
    { type: 'numeric' },
    { type: 'autocomplete' }
  ]
});

table.getColumnType = function(col) {
  return table.options.columns[col]?.type ?? null;
}

console.log(table.getColumnType(0));
console.log(table.getColumnType(1));
console.log(table.getColumnType(2));
console.log(table.getColumnType(3));
```

```text:実行結果
text
numeric
numeric
autocomplete
```

* 列のインデックスを指定してセルの形式を取得できる

※Handsontableと違い、範囲指定によるセルの形式の取得は出来ない。

## 設定で渡したスキーマを取得する
Handsontableの`getSchema`のような機能はない。

## セルを選択する・選択されたセルを取得する
Handsontableの`selectCell`の機能に近いものは、`updateSelection`と`updateSelectionFromCoords`にあたる。
Handsontableの`getSelected`がないため、別途関数を作成する必要がある。

```js
let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  minDimensions: [5,5],
});

// table.updateSelection(table.getCell('B1'), table.getCell('C3'), true);
table.updateSelectionFromCoords(1, 0, 2, 2);

table.getSelected = function() {
  let colSelect = this.getSelectedColumns();
  let rowSelect = this.getSelectedRows();

  let ret = [];
  ret.push(colSelect[0]);
  ret.push(Number(rowSelect[0].dataset.y));
  ret.push(colSelect.slice(-1)[0]);
  ret.push(Number(rowSelect.slice(-1)[0].dataset.y));

  return ret;
}

console.log(table.getSelectedColumns());
console.log(table.getSelectedRows());
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/a4a5d2bf-7835-4a2b-932e-0b8b7bbd8af7.png)

* `updateSelectionFromCoords()`でセルを選択できる
  * 最初に2つが選択の開始位置、後ろ2つが選択の終了位置
* `updateSelection()`でもセルを選択できる
  * 開始セルと終了セルを指定する
  * 末尾引数のboolは`onselection`イベントを無視するかどうか
* `selectAll()`はセルを全選択できる
* `getSelected()`で、選択されたセルの座標を取得できる

※Handsontableと違い、`selectCell`の指定は(row, col, row2, col2)の順だが、`updateSelectionFromCoords()`は、(col, row, col2, row2)の順となる。

## プロパティ名指定でセルを選択する
Handsontableの`selectCellByProp`がないため、別途関数を作成する必要がある。

```js
let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  data: [
    { name: 'aaa', age: 12 },
    { name: 'bbb', age: 15 },
    { name: 'ccc', age: 18 }
  ],
  columns: [
    { title: 'name', name: 'name', type: 'text', align: 'left', width: 100 },
    { title: 'age', name: 'age', type: 'numeric' },
  ]
});

table.propToCol = function(prop) {
  const getIndex = (arr, target) => arr.findIndex(item => item.name === target);
  return getIndex(table.options.columns, prop);
}

table.selectCellByProp = function(row, prop) {
  const col = this.propToCol(prop);
  this.updateSelectionFromCoords(col, row, col, row);
}

table.selectCellByProp(1, 'age');
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/c851c59d-7293-4fe0-9dcc-01ead73aa1aa.png)

* `updateSelectionFromCoords()`の列を指定する部分がプロパティ名になった版
* 範囲指定の対応までしていない

※Jspreadsheet CEでは、配列の配列になっておりオブジェクトの配列ではないため、`columns`オプションを利用してプロパティ名(=name)から列のインデックスを取得する。

## 現在選択されているセルの値を取得する
Handsontableの`getValue`と同じ名前のメソッドがあるが機能が違う、機能に近いものは`getData(true)`となる。
Jspreadsheetの`getValue`は引数にセル名(A1形式)を指定した値が取得できる。

```js
let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  data: [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
  ]
});

table.updateSelection(table.getCell('C2'));

console.log(table.getData(true)[0][0]);
```

```text:実行結果
6
```

※Handsontableと違い、戻り値は配列の配列になっているため`getData(true)[0][0]`で取得している。

## データを読み込む
Handsontableの`loadData`との機能に近いものは、`setData`にあたる。

```js
let data = [
  {name: '佐藤', age: 25},
  {name: '鈴木', age: 11},
  {name: '田中', age: 21}
];

let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  data: data
});

// ★データを読み込む
table.setData([
  {name: '御手洗', age: 31},
  {name: '東海林', age: 22}
]);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/e0955025-8966-4f09-a563-fab637a6a89e.png)

* `setData()`メソッドを使えば、データを上書きで読み込みできる

## 空列・行かどうかを確認する
Handsontableの`isEmptyCol`,`isEmptyRow`がないため、別途関数を作成する必要がある。

```js
let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  data: data
});

table.isEmptyCol = function(col) {
  const isAllNull = (arr) => arr.every(value => !value);
  return isAllNull(this.getDataAtCol(col));
}

table.isEmptyRow = function(row) {
  const isAllNull = (arr) => arr.every(value => !value);
  return isAllNull(this.getDataAtRow(row));
}

console.log(table.isEmptyCol(1));
console.log(table.isEmptyCol(2));
console.log(table.isEmptyRow(1));
console.log(table.isEmptyRow(2));
```

```text:実行結果
false
true
false
true
```

* インデックス指定で行または列が空かどうかを確認できる

## 配列でデータを埋め込む
Handsontableの`populateFromArray`のような機能はありません。

`setValue`メソッドの引数にセル名(A1形式)と値をセットすることで値を書き換えることができるため、それを利用した関数を作成すればいい。

## プロパティ名から列のインデックスを取得する
Handsontableの`propToCol`がないため、別途関数を作成する必要がある。

```js
let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  data: [
    { name: 'Sato',   age: 14, sex: 'male'   },
    { name: 'Suzuki', age: 16, sex: 'female' },
    { name: 'Tanaka', age: 18, sex: 'male'   }
  ],
  columns: [
    { title: '名前', name: 'name', type: 'text', align: 'left', width: 100 },
    { title: '年齢',  name: 'age',  type: 'numeric' },
    { title: '性別',  name: 'sex',  type: 'text' },
  ]
});

table.propToCol = function(prop) {
  const getIndex = (arr, target) => arr.findIndex(item => item.name === target);
  return getIndex(table.options.columns, prop);
}

console.log(`age = ${table.propToCol('age')}`);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/51407984-4c78-4ee3-aace-aae65dd24b1d.png)



* プロパティ名を指定して、そのプロパティの列のインデックス値を取得できる

※Jspreadsheet CEでは、配列の配列になっておりオブジェクトの配列ではないため、`columns`オプションを利用してプロパティ名(=name)から列のインデックスを取得する。

## インデックスからプロパティ名を取得する
Handsontableの`colToProp`がないため、別途関数を作成する必要がある。

```js
let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  data: [
    { name: 'Sato',   age: 14, sex: 'male'   },
    { name: 'Suzuki', age: 16, sex: 'female' },
    { name: 'Tanaka', age: 18, sex: 'male'   }
  ],
  columns: [
    { title: '名前', name: 'name', type: 'text', align: 'left', width: 100 },
    { title: '年齢',  name: 'age',  type: 'numeric' },
    { title: '性別',  name: 'sex',  type: 'text' },
  ]
});

table.colToProp = function(col) {
  return this.getHeader(col);
}

console.log(`2 = ${table.colToProp(2)}`);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/a7d90d6f-0481-4631-8567-ce072ebfe9ca.png)

* `propToCol`の逆

## グリッドを再描画させる
Handsontableの`render`との機能に近いものは、`setData`と'updateTable'にあたる。

```js
let data = [
  { name: '佐藤', age: 25 },
  { name: '鈴木', age: 11 },
  { name: '田中', age: 21 }
];

let grid = document.getElementById('grid');

let table = new jspreadsheet(grid, {
  data: data
});

data.push({ name: '山田', age: 22 });

// 再描画
table.setData(data);
table.updateTable();
```

* データの内容を変更したあとで `setData()`メソッドを実行するとデータが反映される
* `updateTable()`メソッドは描画のみ