Angular Spreadsheet Component | ng-hub-ui-spreadsheet
Editable Angular spreadsheet with Excel's keyboard, rectangular selection, a clipboard that round-trips with Excel, frozen panes and merged cells. MIT, accessible, no paid tier.
API リファレンス
spreadsheet の完全な仕様をここにまとめました。バインド、リッスン、プロジェクション、テーマ設定ができるすべてが一か所に集約されています。必要なものを接続し、好きなようにスタイリングしてください — standalone で signal フレンドリーです。
インプット
31 個のインプットで spreadsheet を調整。通常の Angular @Input と同じようにバインドできます。
| 名前 | 型 | デフォルト | 説明 |
|---|---|---|---|
rows必須 | readonly TRow[] | — | The rows, as you hold them. The sheet never writes to them. |
columns必須 | readonly HubSpreadsheetColumn<TRow>[] | — | What each column shows and allows. |
rowKey必須 | (row: TRow) => string | — | A stable name per row, so a save state follows its row across a reload. |
errors | Record<string, string> | {} | A validation message per cell, keyed like `states`. Owned by the host, because validation belongs to whoever knows what the data means. |
states | Record<string, HubSpreadsheetCellState> | {} | Save state per cell, keyed by the row key and the column alias joined by a tab. |
decimalMark | ',' | '.' | ',' | The character this reader types decimals with. Only consulted when a pasted value carried no raw number. |
emptyText | string | '' | What an empty sheet says. |
pageSize | number | 10 | How many rows Page Up and Page Down travel. |
readonly | boolean | false | Turns off every editor, whatever the individual cells say. |
frozenColumns | number | 0 | How many columns stay pinned to the leading edge, counted the way Excel freezes panes. |
frozenRows | number | 0 | How many rows stay pinned below the header. |
spans | readonly HubGridSpan[] | [] | Merged blocks, each named by its top-left corner and its extent. |
fillHandle | boolean | false | Whether the sheet offers the fill handle at the corner of the selection. |
canUndo | boolean | false | Whether undo is available. The sheet only asks; the owner keeps the history. |
canRedo | boolean | false | Whether redo is available. |
resizableColumns | boolean | false | Whether a reader may drag a column's trailing edge to widen or narrow it. |
reorderableColumns | boolean | false | Whether a reader may drag a header to put the column somewhere else. |
columnWidths | Record<string, number> | {} | The width of each column in pixels, keyed by alias. Two-way: the sheet writes it as the reader drags, and you may persist it. |
minColumnWidth | number | 48 | The narrowest a column may be dragged. |
virtual | boolean | false | 表示領域が覆う行だけを描き、残りの高さを確保します。数千行のシート向けです。既定では無効で、代償もあります。視界の外の行は文書に入っていないので、ブラウザの検索も印刷も描かれている分しか届かず、行の高さはそろっている必要があります。有効にするとシートに 24rem の高さも与えます。伸びるに任せたシートは中身と同じ高さになり、そうなると仮想化するものが残らないからです。 |
rowHeight | number | 0 | 仮想化中の行の高さ(ピクセル)。0 なら最初に描いた行を測ります。行がそろっている限りそれで正しく、隠れたまま組み立てるシートでは明示してください。一度も配置されていない行は 0 と測られ、0 から求めた窓はシート全体になります。 |
formulas | boolean | false | 値が = で始まるセルを数式として読むかどうか。頼まれるまで無効です。テキストの列が =1+1 を「誰かが書いた文字列」として持っていて何もおかしくないからです。数式は列を別名で指せます — =[units] * [price]、=SUM([total:]) — 列を動かしても見出しを書き直しても意味は変わりません。表計算ソフトと同じ坐標でも指せます — =ROUND(SUM(E1:E4), 2) — その場合は「どの列か」でなく「どこにあったか」を言っているので、rewriteRowFormulas() がシートの形の変化に合わせて移し、消えたものへの参照は隣をこっそり読むのではなく #REF! になります。コロンは列全体を読み、尋ねているセルだけを外します。ほかの循環は追いかけずに #CYCLE! として見せます。 |
mergeable | boolean | false | 読み手がセルを結合し、また解除できるかどうか。コンテキストメニューから提供するので contextMenu も必要です。構造を変えるものはすべてそうであるように、頼まれるまで無効です。 |
editOn | 'click' | 'double-click' | 'double-click' | ポインタで編集を開くきっかけ。既定はダブルクリックで、表計算の慣習です。クリックはセルを選ぶだけで値には触れず、最初に打った文字が編集を開いてそのまま入り、一覧や日付を持つセルには一度のクリックで開く印が出ます。書き込むためのシートなら click にすると最初のクリックで開きます。どちらでも編集はボタンを離したときに、しかもポインタが動かなかったときだけ開くので、範囲のドラッグはそのまま使えます。 |
contextMenu | boolean | false | Whether a right-click offers the menu of structural changes. Each entry still has to pass the permissions, and the menu is never opened empty. |
columns[].kind | 'text' | 'number' | 'currency' | 'date' | 'boolean' | 'select' | 'text' | How the column shows its values and reads back what is typed. A select column opens a list and refuses anything not on it; a boolean draws a checkbox that turns over in one click; a date opens a date field. |
columns[].formula | string | — | この列のすべてのセルを導く数式。データに持たせるのではなくコードで宣言します。明細の合計、税、繰越残高などです。読み手が打つ数式とは逆で、あちらは行が持つ値であり、ほかの値と同じように変えられます。この列のセルはそもそも開けません。一つを置き換えるとその行だけ数式が消え、合計が合わなくなるまで誰も気づかないからです。シート側の formulas が必要です。 |
columns[].placeholder | string | — | A hint shown in an empty cell of this column while the pointer rests on it. Never in place of a value: a column of hints always on screen reads as a column of content. |
columns[].options | readonly HubSpreadsheetOption[] | — | The answers a select column offers. A cell shows the matching label rather than the stored value, and falls back to the raw value when nothing matches, so a row holding a retired option stays readable. |
structure | HubSpreadsheetStructureOptions<TRow> | {} | Which structural changes the reader may ask for. Everything is refused until allowed. |
retiredColumnKeys | readonly string[] | [] | Aliases of columns that were deleted, so a new one never inherits a dead identity. |
アウトプット
spreadsheet の動作に反応 — ロジックを接続できる 12 個のイベント。
| 名前 | 型 | 説明 |
|---|---|---|
commit | HubSpreadsheetCommit<TRow> | A cell took a new value, and it differs from the one it held. |
pasted | HubSpreadsheetPaste<TRow> | A block was pasted, with counts of what fell outside the sheet and what was not a number. |
cleared | HubSpreadsheetCellRef<TRow>[] | Delete was pressed over a selection; carries the editable cells it covered. |
selectionChange | HubGridRange | null | The selected rectangle changed. |
filled | HubSpreadsheetPaste<TRow> | A drag of the fill handle finished, reported as one event for the whole gesture. |
undoRequested | void | The reader asked to undo. |
redoRequested | void | The reader asked to redo. |
columnMoved | { from: number; to: number; key: string; keys: string[] } | A column was dropped somewhere else. Reported, not applied: the payload carries the aliases already reordered. |
mergeRequested | HubSpreadsheetMergeRequest | 選択範囲の結合が求められました。作る結合と、それが飲み込む結合の基点が渡されます。前者だけ足して後者を外さないと、同じセルを二つの結合が主張することになります。applySpanMerge() が一行で片づけます。 |
unmergeRequested | readonly HubGridCoords[] | 選択範囲が触れている結合の解除が求められました。基点で示されます。applySpanUnmerge() で適用します。 |
insertRequested | HubSpreadsheetInsertRequest | The reader asked to add rows or columns. |
deleteRequested | HubSpreadsheetDeleteRequest | The reader asked to remove rows or columns, naming the aliases at stake. |
メソッド
spreadsheet をコードから操作 — プログラム操作のための 17 個のメソッドを備えています。
| 名前 | シグネチャ | 戻り値 | 説明 |
|---|---|---|---|
sheetToXlsx | sheetToXlsx<TRow>(rows, columns, options?: HubXlsxOptions): Uint8Array | Uint8Array | シートを本物の .xlsx として、バイト列で返します。数値は数値のまま、日付列は日付になります。CSV では運べないものです。書き出すのはセルが見せている値で、リスト列はラベル、数式は結果です。行が持つ値そのものが要るときは values: 'stored' を渡します。 |
downloadXlsx | downloadXlsx(filename: string, bytes: Uint8Array): void | — | そのブックを保存用として読み手に渡します。名前に .xlsx がなければ付けます。どのホストも同じ六行を書き、object URL の解放を忘れるので、ここに置いてあります。 |
xlsxToRecords | xlsxToRecords<TRow>(bytes, columns, options?: HubXlsxReadOptions): Promise<Array<Record<string, string>>> | Promise<Array<Record<string, string>>> | ブックの最初のシートを、列の別名をキーにした行として読みます。CSV には無い二つのこと——共有文字列と、日数として保存された日付——を元に戻します。本物のブックは圧縮されており、展開はプラットフォームの機能を使うので非同期です。 |
sheetToCsv | sheetToCsv<TRow>(rows, columns, options?: HubCsvOptions): string | string | シートを CSV として返します。区切り文字を指定しなければ小数点記号から決まります。小数点に使う文字で区切ることはできないので、1.234,56 と書く環境向けのファイルにはセミコロンを使います。 |
downloadText | downloadText(filename: string, text: string, type?: string): void | — | テキストファイルを保存用として読み手に渡します。表計算ソフトが UTF-8 として開くためのバイト順マークを付けるので、文字化けしません。 |
csvToRecords | csvToRecords<TRow>(text, columns, options?: HubCsvOptions): Array<Record<string, string>> | Array<Record<string, string>> | CSV を、列の別名をキーにした行として読みます。区切り文字は決め打ちせず一行目から見分けます。見出しはまず見出しで、次に別名で突き合わせ、大文字小文字と前後の空白は無視します。 |
sheetValues | sheetValues<TRow>(rows, columns, options?: HubSheetValuesOptions): HubSpreadsheetValue[][] | HubSpreadsheetValue[][] | 各セルが持つ値。数式は計算済みで、失敗した数式は表計算ソフトと同じ綴りで入ります。二つの書き出しが読んでいるのはこれで、独自のファイルを書くホストのために公開しています。 |
evaluateSheet | evaluateSheet<TRow>(input: HubFormulaSheetInput<TRow>): HubFormulaSheet | HubFormulaSheet | シートの数式をすべて、依存関係が要求する順で実行します。必要になった時に計算し、覚えておきます。循環は閉じた瞬間に捕まえ、追いかけません。描画せずに答えだけが欲しいホストのために公開しています。 |
rewriteRowFormulas | rewriteRowFormulas<TRow extends object>(rows, change: HubFormulaShapeChange): TRow[] | TRow[] | シートの形が変わったとき——列が移動した、行や列を挿入した、削除した——行の中の座標をすべて動かします。消えたものへの参照は、隣をこっそり読むのではなく #REF! になります。行はホストのものなので、呼ぶのはホストです。 |
mergeRequestFor | mergeRequestFor(spans, range): HubSpreadsheetMergeRequest | null | HubSpreadsheetMergeRequest | null | 選択範囲がなるはずの結合ブロックと、それが飲み込むアンカー。単一セルなら null です。飲み込むアンカーはホストが自力でやると間違えるところで、外さずに追加すると二つのブロックが同じセルを主張します。 |
applySpanMerge | applySpanMerge(spans, request: HubSpreadsheetMergeRequest): HubGridSpan[] | HubGridSpan[] | その結合のあとのブロック一覧。飲み込まれたものは落ちます。 |
applySpanUnmerge | applySpanUnmerge(spans, anchors: readonly HubGridCoords[]): HubGridSpan[] | HubGridSpan[] | それらを分解したあとのブロック一覧。 |
spreadsheetRecords | spreadsheetRecords<TRow>(rows, columns): HubSpreadsheetRecord[] | HubSpreadsheetRecord[] | 各行を、列の別名をキーにした素のデータとして返します。座標を位置で自分のフィールドに割り当てるのではなく、{ price: 12, units: 3 } を扱えます。 |
parseForColumn | parseForColumn<TRow>(text, column, decimalMark: ',' | '.'): HubSpreadsheetValue | undefined | HubSpreadsheetValue | undefined | 打ち込まれた、あるいは貼り付けられた文字列が、その列でいくらになるか。値、空セルなら null、その列が持てないものなら undefined を返すので、呼ぶ側はゴミを保存せずに断れます。 |
nextColumnKey | nextColumnKey(taken: Iterable<string>, prefix?: string): string | string | ほかの列のものだったことが一度もない別名。新しい列が引退した名前を使い回さないので、保存済みの参照が別のものに解決されることがありません。 |
danglingColumnKeys | danglingColumnKeys<TRow>(referenced: Iterable<string>, columns): string[] | string[] | もうどの列にも解決しない参照。つまり削除が宙ぶらりんに残すもののことです。 |
provideHubSpreadsheetControls | provideHubSpreadsheetControls(adapter: HubSpreadsheetControlsAdapter): EnvironmentProviders | EnvironmentProviders | コントロールのアダプターを登録します。以後すべてのリスト列がそれで開きます——検索付きで、すでに開いた状態で、セルを開いた文字を検索欄に入れて。アダプターが無ければシートはネイティブのリストを描き、それがこのライブラリ単体で入れられる理由です。 |
テンプレート
自分好みに — 2 個のテンプレートスロットでカスタムマークアップをプロジェクションできます。
| 名前 | 説明 | サンプル |
|---|---|---|
hubSpreadsheetEditor | 指定した別名の列の編集をテンプレートに差し替えます。テンプレートには値と commit・cancel の組、そして `seed`(読み手が入力して開いたときの最初の文字。ピッカーの検索欄に入れるもの)が渡されます。どちらかを呼ぶまで開いたままで、シートは中身に依存しません。 | <ng-template hubSpreadsheetEditor="assignee" let-value let-seed="seed" let-commit="commit">
<hub-select [items]="people" autoOpen [initialSearchTerm]="seed ?? null" [ngModel]="value" (ngModelChange)="commit($event)" />
</ng-template> |
hubSpreadsheetCell | 編集していないあいだの列のセルを自分で描きます。状態のバッジ、名前の横のアバター、並んだアクションなど。セルのもう半分を受け持つ hubSpreadsheetEditor の対になるものです。クリップボードには描いたものではなく値が乗り、キーボードが立っているのは変わらずセルです。hubSpreadsheetCellRows で行を渡せば、コンパイラは `row` が何かを知ります。 | <ng-template hubSpreadsheetCell="state" let-value>
<hub-badge variant="soft" [color]="colourOf(value)">{{ labelOf(value) }}</hub-badge>
</ng-template> |