かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

JavaScript data-属性の操作

VDOMなフレームワークを使っているとHTMLの属性を直接触る機会はあまりないと思いますが、カスタムデータ属性 data-* の操作には getAttribute / setAttribute より dataset を使うと簡単です。

カスタムデータ属性 data-*

カスタムdata属性の名前はdata-で始まる。また、カスタムdata属性名は文字、数字とダッシュ(-)、ドット (.)、コロン (:)、アンダースコア (_)しか含むことができない。さらに、ASCIIコードの大文字AからZも含むことができない。
ref. HTMLElement.dataset - Web API | MDN

dataset

Element.dataset でカスタムデータ属性が key: value で入ったオブジェクトとして扱える

<div id="elm"
  data-name="Hoshimiya Ichigo"
  data-type="cute"
  data-name-ja="星宮いちご">
</div>
const elm = document.getElementById('elm');
console.log(elm.dataset);
/* DOMStringMap
{
  name: "Hoshimiya Ichigo"
  nameJa: "星宮いちご"
  type: "cute"
}
*/

ハイフン繋のカスタムデータはkeyがキャメルケースに変換される。

データの取得と変換

dataset はオブジェクトなので、通常のオブジェクトのようにカスタムデータ属性の取得・更新を行うことができる

<div id="elm"
  data-name="foo"
  data-my-val="bar"
  data-count="0"
></div>
data-* の取得
const elm = document.getElementById('elm');
elm.dataset.name; // => "foo"
elm.dataset.myVal; // => "bar"
elm.dataset.count; // => "0"
data-* の更新
elm.dataset.name = 'bar';
elm.dataset.myVal += 'ely';
// => <div id="elm" data-name="bar" data-my-val="barely" data-count="0"></div>

カスタムデータは文字列で取得されるので扱いには注意が必要

elm.dataset.count += 1;
// elm.dataset.count は "0" なので文字列結合される
// => <div id="elm" data-name="bar" data-my-val="barely" data-count="01"></div> 
data-* 属性の追加

存在しないキーに値を渡すと DOM にカスタムデータ属性が追加される。
キャメルケースの key は ハイフン - つなぎに変換されて DOM に追加される。

// <div id="elm"></div>
const elm = document.getElementById('elm');
elm.dataset.name = "foo";
elm.dataset.someVal = "bar";
// => <div id="elm" name="foo" data-some-val="bar"></div>
data-* 属性の削除

Element.dataset で空文字を入れても属性そのものは削除されない

// <div id="elm" name="foo"></div>
const elm = document.getElementById('elm');
elm.dataset.name = "";
// => <div id="elm" name></div>
elm.dataset;
// => DOMStringMap {name: ""}

nullundefinedNaN を渡すと"null", "undefined", "NaN"という文字列がカスタムデータ属性の値として設定される

カスタムデータ属性自体を削除するには delete 演算子removeAttribute を使う

delete elm.dataset.name;
// 又は
elm.removeAttribute('data-name');
// => <div id="elm"></div>
elm.dataset;
// => DOMStringMap {}

カスタムデータ属性の名前が正しくない場合

e.g. キャメルケースになっている場合

<div id="elm" data-idolName="霧矢あおい"></div>
const elm = document.getElementById('elm');
elm.dataset.idolName; // => undefined
elm.getAttribute('data-idolName'); // => "霧矢あおい"

Element.dataset ではそのままの key で値を取得することができない。

キャメルケースになっている key は lowercase されている

console.log( elm.dataset );
// => DOMStringMap {idolname: "霧矢あおい"}
elm.dataset.idolname; //=> "霧矢あおい"
まとめ

Element.dataset を使うとオブジェクトを扱うように カスタムデータ属性 (data-*)が扱えるのでとても良さげです。
だだし、大文字は使えないことになっているのに違反しているようなカスタムデータ属性が使われている場合、注意が必要そうです。(HTML側を修正するようにPRするか、レビューで通さないようにするのが良いと思います)


[参考]

Kiss Me/Hold Me Now

Kiss Me/Hold Me Now

  • アーティスト: キャロル&チューズデイ(Nai Br.XX&Celeina Ann)
  • 出版社/メーカー: フライングドッグ
  • 発売日: 2019/05/29
  • メディア: CD
  • この商品を含むブログを見る
👆今期やってるアニメの キャロル&チューズデイ がとても良い

Ruby gem install bundler で Permission denied エラーになった

こんにちは。今日は6月6日、D-dayだった日です。そんな日にエラーを出したのでメモ。
rbenv で Ruby のバージョンを管理していて、rbenv でインストールした別の Ruby のバージョンを切り替えた後に gem install bundler しようとしたら Permission denied @ rb_sysopen のエラーが出てしまいました。

rbenv でインストールしたものにパーミッションがおかしいモノがある

一応 通常通り rbenv でインストールしたものが /Users/{user_name}/.rbenv/ 内にあるか確認します。

$ which ruby
/Users/{user_name}/.rbenv/shims/ruby
$ which gem
/Users/{user_name}/.rbenv/shims/gem
$ rbenv versions
  system
  2.5.1
* 2.5.5 (set by /Users/{user_name}/.rbenv/version)

rbenv でインストールしたものが使われています。
どこかで system のものと間違って sudo gem install などで sudo でインストールしたものがあり、ユーザーにパーミッションがないディレクトリ / ファイルが出来てしまっているのが原因な可能性が高そうです。(つまり自分のせい…)

rbenv のディレクトリのパーミッションをなおす

$ sudo chown -R {user_name}:staff /Users/{user_name}/.rbenv
パーミッションの確認
$ cd ~/User/.rbenv
$ ls -la
total 8
drwxr-xr-x   5 {user_name}  staff   160  6  9  2018 .
drwxr-xr-x+ 70 {user_name}  staff  2240  6  6 17:58 ..
drwxr-xr-x  75 {user_name}  staff  2400  6  6 18:37 shims
-rw-r--r--   1 {user_name}  staff     6  6  4 10:21 version
drwxr-xr-x   4 {user_name}  staff   128  5 27 15:25 versions

ユーザー名が表示されていればOK

gem のアップデートと bundler の再インストール、
$ gem update
$ gem install bundler

エラー無く実行されればOK 🎉

教訓

rbenv で新ストールした Ruby を使っている時は sudo gem install を使ってはいけない。


[参考]

スラスラ読める Rubyふりがなプログラミング (ふりがなプログラミングシリーズ)

スラスラ読める Rubyふりがなプログラミング (ふりがなプログラミングシリーズ)

D-dayといえば バンド・オブ・ブラザース 時々アマプラで見返してしまう。

Google スプレッドシート 自動的に生年月日の列から年齢を計算したい

Spreadsheet に次のような誕生日の入ったデータがあり、自動的に今、何歳なのか表示させたい。

A B C
1 名前 誕生日 年齢
2 星宮いちご 1999/03/15
3 霧矢あおい 1999/01/31
4 紫吹LAN 1998/08/03
5 藤堂ユリカ 1998/12/26
6 大空あかり 2000/04/01
7 神崎美月 1996/09/18
8 北大路さくら 1999/04/06
9 夏樹みくる
10 天羽まどか 2002/02/14

要件の整理

  1. 年齢は今日何歳かで表示する
  2. データが増えていったら自動的に年齢も計算される
  3. 誕生日が未入力の行は年齢計算をスキップする

一度にやろうとすると複雑なので、1つ1つの要件を実現して組み合わせればOK。
問題は分解しましょう。

1. 誕生日から今日何歳かを計算する

誕生日の計算は今年から誕生日の年数を引いて、誕生日の日付がまだ来ていない(今日より後)なら -1 すればOK。 条件分岐は IF(条件, TRUE値, FALSE値) を使う。falseのときの値が不要なら省略可。

# B2: 1999/03/15
=(YEAR(NOW()) - YEAR(B2) + IF(B2 > TODAY(), -1) & ""

=> 20歳
& を使って計算結果に "歳" という文字を結合しています

2. 範囲に自動的に計算結果が入力されるようにする

範囲に計算式を適応するには ARRAYFORMULA 関数を使用します。
ざっくりいうと、計算式に使う対象を範囲にすれば、計算結果が配列で返され該当する範囲に計算結果が表示される。みたいな感じ

上の例だとB列のB2セル以降を自動で計算してC列に結果を入れたいので、C2 セルに計算式を記述します。
自動的に年齢計算した結果を入れるだけでなので 1. の計算式の対象を範囲にすればOK

# C2セルに式を記入
=ARRAYFORMULA( (YEAR(NOW()) - YEAR(B2:B) + IF(B2:B > TODAY(), -1) & "" )

=> C列に年齢を計算した結果が自動的に入る

A B C
1 名前 誕生日 年齢
2 星宮いちご 1999/03/15 20歳
3 霧矢あおい 1999/01/31 20歳
4 紫吹LAN 1998/08/03 21歳
5 藤堂ユリカ 1998/12/26 21歳
6 大空あかり 2000/04/01 19歳
7 神崎美月 1996/09/18 23歳
8 北大路さくら 1999/04/06 20歳
9 夏樹みくる 120歳
10 天羽まどか 2002/02/14 17歳
11 120歳

データが増えれば自動的に誕生日をC列に表示するようにはできましたが、このままでは計算対象のセルが空白の場合もデフォルトの日付?から計算されてしまい値が入力されてしまいます。

3. 誕生日が未入力の場合は年齢計算をしない

IF文を追加して誕生日が空白でなければ、年齢を計算し、空白ならセルを空にします。
空白でないときの条件式は次のような感じ

= B <> ""

他の言語のイメージで B != "" としたら #ERROR になってしまいました…

  1. で作成した計算式に条件を追加します。
# C2セルに式を記入
= IF(B2:B <> "", ARRAYFORMULA( (YEAR(NOW()) - YEAR(B2:B) + IF(B2:B > TODAY(), -1) & "" ), "")

falseのときは明示的に空文字""を返すようにしないとFALSEという文字が入力されてしまう
👇

A B C
1 名前 誕生日 年齢
2 星宮いちご 1999/03/15 20歳
3 霧矢あおい 1999/01/31 20歳
4 紫吹LAN 1998/08/03 21歳
5 藤堂ユリカ 1998/12/26 21歳
6 大空あかり 2000/04/01 19歳
7 神崎美月 1996/09/18 23歳
8 北大路さくら 1999/04/06 20歳
9 夏樹みくる
10 天羽まどか 2002/02/14 17歳
11

 
これで、データがある行だけ自動的に年齢を表示できるようになりました。
いきなり ARRAYFORMULA で式を作ると結果が解りにくい時は、特定のセルで正しく計算できる式を作ってから対象を範囲に変更するとハマりにくいと思います。

ところで、みくる姉さん最年長らしいけど、美月さんの何歳年上なんだ… (ここでメッセージは途絶える


[参考]