Gatsby + Airtableサイトのトップページに記事をフラッグする機能を追加してみた
2019年1月26日2019年1月27日
Gatsbyで作っているこのサイトで、上のキャプチャのような感じで、オンゴーイングのノートをトップページの上部にフラッグする機能をつけようと思って作業をしています。
Airtableに項目を追加
まずはAirtableにflag
というチェックボックス(true / false)の項目を追加。この項目にチェックを入れるとトップページの「FLAGGED」セクションにノートを表示するようにしたい。
※最終的にはSingle select
に変更しました。
GraphQLのクエリでやってみる
まずは以下のGraphQLクエリを追加してフラッグを立てた記事を表示させてみました。filter
を使ってflag
にチェックの入った行だけを引っ張ってくるようにクエリを書きました(ハイライトされている4行目の部分)。
flagged: allAirtable(
filter: {
table: {eq: "entry"},
data: {flag: {ne: null}} }
) {
edges {
node {
data {
title
slug
}
}
}
}
ただ、これだとチェックされている項目がない場合に以下のエラーが出てしまいます。簡単に行かないですね。
error Field "flag" is not defined by type airtableConnectionDataInputObject_2;
先ほど追加したAirtableのflag
というフィールドにチェックが入っている項目が一つもないと、そのフィールド自体を引っ張ってこられない仕様になってるんですかね?この辺はソースプラグインの仕様なのか、それともGraphQLの仕様なのか?わからない...
ということで、記事一覧の出力用のクエリで引っ張ってきたデータをJavaScriptのfilter()
メソッドを使ってflag
のついた項目の有無を判別してやってみようと思います。
JavaScriptのfilter()メソッドを使う方法
以下、JSのfilter()
を使って実装する方法の記録です。
Airtableの項目をSingle selectに変更
まず、追加したflag
フィールドのfield type
をSingle select
に変更してflagged
と空(Empty)のオプションを追加しました。
記事一覧用のクエリにflagを追加
記事一覧を引っ張ってくるクエリにflag
を追加します。
posts: allAirtable(
sort: { fields: [data___date], order: DESC },
filter: { table: {eq: "entry"}},
) {
totalCount
edges {
node {
data {
slug
title
date(formatString: "YYYY年M月D日")
flag }
}
}
}
記事一覧からフラッグされたものを抽出
上記クエリで取得したデータからfilter()
を使って、flag
でflagged
が選択された記事を抽出します。
const posts = this.props.data.posts;
const flagged = flaggedPosts(posts);
function flaggedPosts(posts) {
let flagged = posts.edges.filter((a) => {
return a.node.data.flag === "flagged";
});
if(typeof flagged === "undefined" || flagged.length === 0){
return null;
}
return(
<div className={styles.flagged}>
<h2>FLAGGED</h2>
<ul>
{flagged.map(({ node }, index) => (
<li key={index}>
<Link
to={`${node.data.slug}/`}
>{node.data.title}
</Link>
</li>
))}
</ul>
</div>
)
}
1つもフラッグされてない場合にUnknown fieldエラーが出てしまう
記事一覧の出力用のクエリをJavaScriptのfilter()
メソッドを使って...と思ったのですが、GraphQLのクエリにflag
を追加すると、チェックされた項目が一つもない場合にエラーが出てしまいます。
error GraphQL Error Unknown field `flag` on type `data_2`
仕方がないので、さっきflag
フィールドに追加した空のオプションを記事に追加。これで強制的にflag
が選択された項目を作りました。JavaScriptのfilter()
ではflagged
が選択された項目を抽出しているので、空(Empty)が選択された記事は抽出されません。
let flagged = posts.edges.filter((a) => {
return a.node.data.flag === "flagged";
});
これでとりあえず実装は完了しました。
ハック的なやり方で好きじゃないですが、仕方がないので他の方法が見つかるまでは、この方法で妥協しておこうと思います。