Ionic v3でのmulti picker実装とそのハマりポイント & 解決策
KinecaエンジニアのA.Takeguchi | CTO@キネカです。今回はIonic v3でmulti pickerを実装した時にハマった話を備忘録形式で書いていこうと思います。
今回は、 ion-multi-pickerを使用しています。しかし、このpackageは2年以上メンテナンスされていないため非推奨です。後述しますが、今から実装する人はPickerController(ドキュメントなし)を使用するのが良いでしょう。その実装方法の具体例としてion-multi-pickerを参照するのが良いです。
※Ionic v4では公式にmulti pickerが提供されています。Ionic v4への移行を進めていきましょう!
https://ionicframework.com/docs/api/picker
※弊社では、テックリードの@scrpgilが中心となって、現在Ionic v4への移行が進められています。
なぜion-multi-pickerを使用したのか?
前置きで非推奨と書いておきながら、弊社アプリpatoの新機能でion-multi-pickerを使用しています。
実は弊社では現在Ionic v4へ絶賛移行中であり、またIonic v4になると公式からmulti-pickerコンポーネントが提供されています。そのため今回した実装は一時的にであり、すぐに捨てることがわかっていて、時間をかける必要がなかったためです。
実装する
ion-multi-pickerのREADMEに書いてある通りに進めていけば、初回動かす分には特に困ることなくできるイメージです。
一つ、注意事項としては、READMEにも書いてある通り、
Note: Don’t miss the
item-content
attribute
item-conetntが必須ということです。つまり、ion-item
の子要素である必要があります。
<ion-item>
<ion-label>Simple Picker</ion-label>
<ion-multi-picker
item-content
[multiPickerColumns]="simpleColumns"
>
</ion-multi-picker>
</ion-item>
をHTMLに書き、
this.simpleColumns = [
{
name: 'col1',
options: [
{ text: '1', value: '1' },
{ text: '2', value: '2' },
{ text: '3', value: '3' }
]
},{
name: 'col2',
options: [
{ text: '1-1', value: '1-1' },
{ text: '1-2', value: '1-2' },
{ text: '2-1', value: '2-1' },
{ text: '2-2', value: '2-2' },
{ text: '3-1', value: '3-1' }
]
}
];
}
をTypescript内に書けばすぐに提供されているデモと似たような挙動を実現できました。
ただし、ここから実装要件と合致する挙動を実現させるために3点ほどハマってしまった。。
ion-toggleがcheckedになった時にmulti-pickerを起動させたい。
ion-multi-pickerだけでハマる話ではないのです。Angularを使っていてclickイベントを発火させたい場合にハマります。
はじめに、@ViewChildやらdocument.querySelectorやらでion-multi-pickerのDOM要素を取得してclick()
すれば良いのでは?と思ってましたが、これではclickイベントは発火しません。
対策
dispatchEvent(new Event("click"))
を使用します。こんな感じです
const el: HTMLElement = <HTMLElement>(
document.querySelector("#target")
);
if (el) {
el.dispatchEvent(new Event("click"));
}
ちなみに、HTMLElementの存在確認をしていますが、*ngIf
を使用している場合は描画されるまで待つ必要があるので注意です。TipsとしてはDOM操作をする場合は*ngIf
ではなく[hidden]
を使うとcssによって隠れるだけでDOMは存在しているので、ionViewDidEnter
以降であれば取得されます。
ionCancelはあるが、backdrop clickで消した時に発火されない
ion-multi-pickerは2年間保守されていないpackageです。このような場合は基本的にコードリーディングは欠かせませんね。
まーあるよね、と思いつつコードを読むとREADMEに書いていない(ionChange)
と(ionCancel)
を見つけることができます。この2つを使ってion-multi-pickerのcallback制御ができるなーと思っていたら、なんとbackdropをclickした時の挙動をキャッチする場所がありませんでした。
対策
これを修正するためには少なくともpackageに手を加える必要があるので、そこまではやりませんでした(手を加えて修正可能かはわかりません)
対応策としては、app.scssに
ion-picker-cmp { // ion-multi-pickerが生成するDOM要素
// backdropでcloseさせない
ion-backdrop {
pointer-events: none;
}
}
と追記することです。なんとも残念な。。。良い子は真似しないようにしましょう!!
Cancel or Doneしてion-multi-pickerが閉じたあとスクロールできなくなる
multi-pickerのセレクトを終了し、キャンセルまたはDoneを押してmulti-pickerを閉じた後はスクロールができなくなります。スクロールはできないが、clickイベントは発生します。これが最強のハマりポイントです。
勘の良い方は「pointer-events: none
やってるからでは?」と思うかもですが、ion-multi-pickerが提供しているデモでも発生します。我々の実装とは無関係に発生しています。
対策
しっかり目に追っていくと、なんだかion-multi-pickerを閉じた後、ion-multi-pickerのDOMの親要素にあるion-content
がpointer-events: none
と同じような挙動になっています。なぜそうなっているのかは最後まで追っていませんが、ion-multi-pickerレイヤではなく、内部的に使用しているIonic v3のPickerController内部が怪しいです。Ionic v3の最新バージョンで発生します。
解決策としてはion-multi-pickerがあるページのscssに
page-example-picker-page {
ion-content {
pointer-events: auto;
}
}
を追記すると修正されます。しかし、反動として、pickerが表示されている間もbackdropの下にあるion-content
をスクロールできるようになってしまいます。これがクリティカルなのであればこの解決策は適用できません。ちゃんとした解決策を探す前にIonic v4へ移行したいですね。
おまけ:PickerControllerとは?
この記事にちょこちょこ出てくるPickerControlerとは何か?を軽く触れておきます。
PickerControllerはIonicのドキュメントに載っていないPickerコンポーネントのコントローラーです。PickerControllerとこの記事で書いているのは、単にIonic v3のPickerコンポーネントと書くとドキュメントに載っていると勘違いされやすいと考えたためです。また、現環境でgoogleで検索するとIonic v4がまずヒットし、そこにはPickerコンポーネントは存在するため、より誤解が進んでしまう可能性があります。そのため、ちょっとわかりにくさを演出したかったのです。
PickerController改め、Ionic v3のPickerコンポーネントはIonic v3のドキュメントに存在しません。よって、これ単体で使用するのは本来は危険です。Ionic v3内のバージョンアップで削除されても文句は言えません。
ただ「そんなこと言ってられないよ!」という人で、なおかつ今回記事で記述した解決策よりもしっかりと実装したい!という人はion-multi-pickerを使わずに自前でIonic v3のPickerコンポーネントを使用する方法が良いかもしれません。幸い、実装例はion-multi-pickerが提供してくれています。ここは実装スピードとトレードオフですね。事業目線でそのスピード感を許容できるのか判断すると良いでしょう。
まとめ
今回はIonic v3におけるion-multi-pickerの実装とその時のハマりポイントを解説しました。解決策はどれも一時しのぎのものです。それはIonic v4では公式からPickerコンポーネントが提供されており、それを利用してmulti-pickerが実装可能となり、Ionic v4になるとion-multi-pickerは使用されなくなるためです。
Ionic v3で、かつスピードを求める方はion-multi-pickerを使用する価値はあります。
結論としては
早くIonic v4へ移行しましょう
ということですね(笑)