#概要
**以前作成したアプリ**の一覧画面をPDFで出力する機能を実装しました。
**vte.cxについて詳しく知りたい方はvte.cxのドキュメント**をご覧ください。
今回実装したPDF出力機能の仕様は以下になります。
- 一覧を表示した状態で「PDF出力」ボタンを押すとPDFをダウンロードする
- 一覧画面に表示されているデータだけをダウンロードする
PDF出力機能を実装するには、サーバーサイドで実行されるサーバーサイドJavaScriptについて知る必要があります。
詳しくはこちらの記事を参考にしてください。
https://qiita.com/stakezaki/items/d596afd085988d76983c
#実装
今回編集したファイルは一覧画面(ListProf)と新しく作ったPDF出力ファイル(ssr.pdf)になります。
では、PDF出力ファイルから見ていきます。
まず、/src/server/
の配下にssr.pdf.tsxファイルを作ってください。
実際のファイルが以下になります。
##PDF出力ファイル(ssr.pdf)
import * as vtecxapi from 'vtecxapi'
import * as React from 'react'
import * as ReactDOMServer from 'react-dom/server'
import * as pdfstyles from '../pdf/pdfstyles'
const PrintToPdf = () => {
const feed = vtecxapi.getFeed('/foo')
const currentPage = Number(vtecxapi.getQueryString('currentPage'))
let sliceFirstNumber = 0
let sliceLastNumber = 5
if(currentPage !== 1) {
sliceFirstNumber = currentPage * 5 - 5
sliceLastNumber = currentPage * 5
}
const showFeed = feed.slice(sliceFirstNumber, sliceLastNumber)
return (
<html>
<body>
<div className="_page" style={pdfstyles._page}>
{feed.length > 0 &&
<table style={pdfstyles._table}>
<tr>
<th style={pdfstyles._th}>名前</th>
<th style={pdfstyles._th}>メール</th>
<th style={pdfstyles._th}>職業</th>
<th style={pdfstyles._th}>住所</th>
<th style={pdfstyles._th}>身長</th>
<th style={pdfstyles._th}>誕生日</th>
<th style={pdfstyles._th}>性別</th>
<th style={pdfstyles._th}>チェック</th>
<th style={pdfstyles._th}>セレクト</th>
<th style={pdfstyles._th}>メモ</th>
</tr>
{showFeed.map((entry) => (
<tr>
<td style={pdfstyles._td}>{entry.user!.name}</td>
<td style={pdfstyles._td}>{entry.user!.email}</td>
<td style={pdfstyles._td}>{entry.user!.job}</td>
<td style={pdfstyles._td}>{entry.user!.address}</td>
<td style={pdfstyles._td}>{entry.user!.height}</td>
<td style={pdfstyles._td}>{entry.user!.birthday}</td>
<td style={pdfstyles._td}>{entry.user!.gender}</td>
<td style={pdfstyles._td}>{entry.user!.check}</td>
<td style={pdfstyles._td}>{entry.user!.select}</td>
<td style={pdfstyles._td}>{entry.user!.memo}</td>
</tr>
))}
</table>
}
</div>
</body>
</html>
)
}
const html = ReactDOMServer.renderToStaticMarkup(PrintToPdf())
// PDF出力
vtecxapi.toPdf(1, html, 'ListProf.pdf')
まずは、PDFファイルに表示させるデータを取得します。
const feed = vtecxapi.getFeed('/foo')
上記のように、vtecxapi.getFeed()
を使うことで、これまで/d/foo
に対して行ってきたGETリクエストをサーバサイドJSから行うことができます。この場合、/foo
に/d
はつけなくて大丈夫です。
これを以下のコマンドでデプロイしてください。
npm run watch:server -- --env.entry=/server/ssr.pdf.tsx
データが取得できたので、実際に表示させてみましょう。
return (
<html>
<body>
<div className="_page" style={pdfstyles._page}>
{feed.length > 0 &&
<table style={pdfstyles._table}>
<tr>
<th style={pdfstyles._th}>名前</th>
<th style={pdfstyles._th}>メール</th>
<th style={pdfstyles._th}>職業</th>
<th style={pdfstyles._th}>住所</th>
<th style={pdfstyles._th}>身長</th>
<th style={pdfstyles._th}>誕生日</th>
<th style={pdfstyles._th}>性別</th>
<th style={pdfstyles._th}>チェック</th>
<th style={pdfstyles._th}>セレクト</th>
<th style={pdfstyles._th}>メモ</th>
</tr>
{showFeed.map((entry) => (
<tr>
<td style={pdfstyles._td}>{entry.user!.name}</td>
<td style={pdfstyles._td}>{entry.user!.email}</td>
<td style={pdfstyles._td}>{entry.user!.job}</td>
<td style={pdfstyles._td}>{entry.user!.address}</td>
<td style={pdfstyles._td}>{entry.user!.height}</td>
<td style={pdfstyles._td}>{entry.user!.birthday}</td>
<td style={pdfstyles._td}>{entry.user!.gender}</td>
<td style={pdfstyles._td}>{entry.user!.check}</td>
<td style={pdfstyles._td}>{entry.user!.select}</td>
<td style={pdfstyles._td}>{entry.user!.memo}</td>
</tr>
))}
</table>
}
</div>
</body>
</html>
)
PDF出力ファイルはJSXで書けますが、ページ構造が決まっています。詳しくはvte.cxのドキュメントのPDFスタイルシートにページ構造が記載されているので、そちらをご覧ください。
データを表示させるテーブルタグの中身は一覧画面とほとんど一緒です。
const html = ReactDOMServer.renderToStaticMarkup(PrintToPdf())
// PDF出力
vtecxapi.toPdf(1, html, 'ListProf.pdf')
ReactDOMServer.renderToStaticMarkup({表示させたいコンポーネント名})
とし、
vtecxapi.toPdf(ページ数,生成元のhtml,PDFのファイル名)
の生成元のhtmlに指定することで、指定したパラメータを元にPDFを生成します。
これで、ブラウザからhttp://{サービス名}/s/ssr.pdf
を開くとPDFファイルがダウンロードされます。
しかし、これだと一覧画面に表示されているデータだけではなく、画像のように全てのデータが表示されてしまうので、表示するデータを指定する必要があります。
const currentPage = Number(vtecxapi.getQueryString('currentPage'))
変数currentPage
に一覧画面のページ数を格納します。
getQueryString(取得したいパラメータ)
とすることで、URLパラメータを取得することができます。
後ほど説明しますが、一覧画面でPDF出力ボタンを押下した際に、ページ遷移と同時に変数 currentPage
の値を同時に送ることで、ページ数を取得します。
let sliceFirstNumber = 0
let sliceLastNumber = 5
if(currentPage !== 1) {
sliceFirstNumber = currentPage * 5 - 5
sliceLastNumber = currentPage * 5
}
const showFeed = feed.slice(sliceFirstNumber, sliceLastNumber)
表示するデータを指定するためには、slice
を使います。そのために、currentPage
を使い、最初と最後の値を指定して抜き出します。
最後に、一覧画面にPDF出力ボタンを配置します。
今回はボタンタグを追加しただけなので、JSXのボタンを配置したところだけ載せておきます。
##一覧画面(ListProf)
return (
<button type="button" onClick={() => location.href="http://vtecx_sample_app.vte.cx/s/ssr.pdf?currentPage="+currentPage}>PDF出力</button>
onClick
イベントにlocation.fref
でURLを指定することで、ボタン押下時にPDF出力ファイルに遷移し、PDFをダウンロードできます。
また、最後にURLの最後に'?currentPage='+currentPage
を追加することで、現在の一覧画面のページ数を一緒に受け渡すことができます。
注意!
一覧画面にボタンを配置した際に、npm run watch:server -- --env.entry=/server/ssr.pdf.tsx
のままになっていると一覧画面を保存しても変更が反映されないので、必ず npm run watch:index
で反映させてください。
これで、実際にボタンを押下してみてください。
こんな感じで、一覧画面と同じデータが表示されたら成功です。
お疲れ様です。