SharePointのJSリンクの改修で、フィールド名がわかりづらく結構手間取ったのでそれについてまとめ
経緯
SharePointにJSリンクというのがあり、Excelでいう条件付き書式を実現するのに使われている(らしい)。
今回対応したのはSharePoint製社内イントラのリストで共通で使っていたJSリンクが、特定のリストで使えないというイレギュラー。原因を調べたところ、そのリストについてはフィールドの内部名が他と異なっていたことが判明。このイレギュラーなリストに対応するために既存のJSリンクのフィールド名のみ修正した差分を作成することになった。
わかりづらい点1: 表示上のフィールド名とJSで取得する内部名が違う
今回の例では表示上のフィールド名は投稿日
、
表示上のフィールド名とJSで取得する内部名が違う、具体的には問題のフィールドは表示上は
大本の原因は以下の2つ
- フィールドの内部名は作成時の作成時のフィールド名をもとに決定され、以降フィールド名を変えても内部名は変わらない
- 全角文字は文字化けしていてそのままでは何のフィールドなのかわからない
厄介なのは後者で、ただでさえ読めない置き換えられた文字が、場合によってはさらにパーセントエンコーディングされていたりもするという…。どうせ置き換えるならパーセントエンコーディングいらない文字列にしてくれればいいのに…。
内部名の取得
列の内部名はというと、列の編集画面のアドレスから見つかる
(詳細はSharePoint 2013 で列の内部名を調べる方法 | idea.toString();を参照)
今回の問題のフィールドの場合、アドレス
http://example.com/(中略)&Field=%5Fx767b%5F%5Fx6821%5F%5Fx65e5%5F
となっていたので、
Field=
に続く%5Fx767b%5F%5Fx6821%5F%5Fx65e5%5F
が内部名になる。
フィールド名が半角文字なら内部名も文字化けせずフィールド名そのままなのでこれで話は終わりになるところだが、今回は見ての通り全角文字なので案の定文字化けている。
パーセントエンコーディングのデコード(必要なら)
今思えば今どきのブラウザなら表示の際にはパーセントエンコーディングをデコードしてくれている気もするのだが、今回1のように何かの拍子でパーセントエンコーディングされることがあるので、その場合デコードする必要がある。
const str = `%5Fx767b%5F%5Fx6821%5F%5Fx65e5%5F`;
const internalname = decodeURI(str);
console.log(internalname); // "_x767b__x6821__x65e5_"が返ってくる
これをデコードすると_x767b__x6821__x65e5_
という内部名が手に入る。
本来の列名の取得
JSリンクで扱う分にはこれで十分だが、やっぱりこれだと何の列だかわからなくてモヤモヤするので変換してみる。
平たく言うとUnicodeらしい。(詳細は日本語で作成した列の内部名から列名を調べる方法 - Qiitaを参照)
せっかくなのでUnicode(¥uxxx形式)を文字列へアンエスケープ | JavaScript逆引き | Webサイト制作支援 | ShanaBrian Websiteを参考に内部名の変換用に関数を作って試してみた。
function decodeInternalname(internalname) {
const re = /_x([0-9a-f]{4})_/g;
const arr = internalname.match(re);
let result = '';
for (str of arr) {
result += String.fromCharCode(str.replace(re, '0x$1'));
}
return result;
};
// 問題のフィールド名を確認する
const internalname = '_x767b__x6821__x65e5_';
const result = decodeInternalname(internalname);
console.log(result); // "登校日"が返ってくる
どうやら投稿日
というフィールドをつくるはずが登校日
と変換間違いしたらしい。
そのまま表示されてたら気になるから結果的に文字化けしててよかったと思った。
わかりづらい点2: ピリオドを含むプロパティ名が存在する。
今回だけならともかく、同様のイレギュラーが今後も全くないとは言えない(実際もう1件あった)ので、差分の作成に先駆けて、簡単に列名を変えられるように列名を定数に切り分けるという改修をした。
具体的には仮にフィールド名がFieldName
だとすると、ctx.CurrentItem.FieldName
といったようになっているのを複数個所修正する必要があったので、これを
var FIELD_NAME = "FieldName";
ctx.CurrentItem[FIELD_NAME];
といった感じで列名を定数に切り出し、'FIELD_NAME'一か所だけ変えれば済むようにした。
問題
そこで問題となったのが以下のようなコード。
ctx.CurrentItem.FieldName.desc
このフィールド名を変数に置き換えようとすると、以下のようにしたくなるが、これはエラーになる
var FIELD_NAME = "FieldName";
(中略)
ctx.CurrentItem[FIELD_NAME].desc // 間違い
結論としては、FieldName.desc
はこれ全体で一つのプロパティ名であって、FieldName
オブジェクトのプロパティdesc
ではない。
そのため正しくは以下のようにする必要があった。
var FIELD_NAME = "FieldName";
(中略)
ctx.CurrentItem[fieldName + ".desc"]
詳細
SharePointのリストは1フィールドが複数の値を持っていることがある。
具体的な例としてはハイパーリンク型のフィールドで、これはURLと説明文の2つの値を持っている。
この場合のプロパティ名はURLがFieldName
、説明文がFieldName.desc
になっているらしい。
GASのようなクラスの詳細がわかるリファレンスがほしいのだけれど見つからなかったので、Chromeのコンソールで調べたところ以下のように確認できた。
console.log(location.pathname) //リストを開いていることを確認。
//"/path/to/list/AnyView.aspx"
console.log(GetCurrentCtx().ListData.Row[0]) // リストの1行目を取得
//{(中略), FieldName: "https://example.com", FieldName.desc: "リンクの説明", (中略)}
その他参考サイト
リストおよびライブラリの列の種類とオプション - SharePoint
decodeURI() - JavaScript | MDN
String.fromCharCode() - JavaScript | MDN
-
この時はブラウザで確認せず、アドレスをその場でコピぺして作業をしたのでパーセントエンコーディングされてしまったらしい。 ↩