AngularでQR/バーコードを使用するInputコントロールを作る
12/1 修正しました。
はじめに
今回のお話は、下記バージョンでお送りします
AngularCLI : 7.0.4
↓みたいなコントロールを作成していきます。
テキストボックスがあり
フォーカスが当たった際に、ソフトウェアキーボードではなくQRを読み込むカメラが起動し
カメラでQRが読み込めた場合
フォーカスが当たっていたテキストボックスに、QRから読み取った値を投入する。
といった動作です。
QR/バーコード読み込み
以前の記事でQRコードを読み取るために、@zxing/ngx-scanner
を使用しました。
今回は、そのライブラリからForkされた、@innotec/ngx-scanner
を使用します。
npm install @innotec/ngx-scanner --save
@zxing/ngx-scanner
の@Inputにはformats
が追加されており、CODE39等のバーコードのFormatを指定することで
バーコードのデータも読み込むことができるようになります。
Formatの指定は、@zxing/library
の Enumで管理されている、BarcodeFormat
の配列を使用します。
Selectorはzxingのngx-scannerと同様なので、下記のようにFormatを指定する部分のみが変わる感じです
<zxing-scanner #scanner [formats]="[BarcodeFormat.QR_CODE, BarcodeFormat.CODE_39]"> </zxing-scanner>
ngx-scannerの使い方は、以前書いた記事を参考にしていただければと思います。
AngularでQRする - はまったりひらめいたり…とか…
Angular Material BottomSheet
画面下からにゅっと飛び出てくるコントロールを作るために
AngularMaterialのBottomSheetコンポーネントを使用しました。
準備
まずは、Materialを使用するために、お決まりの
ng add @angular/material
を行っておきます。
@NgModuleでBottomSheeetのモジュールMatBottomSheetModule
をインポートしておきます。
親コンポーネントからの使用
constructorでMatBottomSheetのDIを行うことで、BottomSheetの処理が使用可能になります。
親コンポーネントから、BottomSheetのOpen()
を実行すればBottomSheetが表示されます。
その際、BottomSheet内に表示するComponentを指定することが可能です。
≪MatBottomSheet≫.open(SheetBodyComponent);
この時BottomSheetに表示されるComponentは、表示されるタイミングでインスタンス化されるようなので
LazyLoadするComponentの時同様、NgModuleのEntryComponentに加えてあげる必要があるようです。
@NgModule({ ... entryComponents: [ SheetBodyComponent ], ... }) export class AppModule { }
サービスの注入
QR/バーコードが読み込まれたタイミングで、親コンポーネントがその結果を引っ掛けたいです
ただ、BottomSheet内のComponentは、EntryComponentなので、@Output
あたりで引っ掛けるのも難しそうです。
なのでDIするClassを作成し、その中のSubjectなプロパティを介して
BottomSheet内Componentと、親Componentでデータのやり取りを行う方法をとろうと思います。
親コンポーネント
// BottomSheetをOpen const res = ≪MatBottomSheet≫.open(SheetBodyComponent); ≪DI Class≫.≪Subjectプロパティ≫.subscribe(x => { // QR/バーコードがScan出来た場合 // InputElementに対して取得したQR結果を突っ込む // ElementRefを使用しInputコントロールを取得する const con = <HTMLInputElement>≪ElementRef≫.nativeElement.querySelector('input'); con.value = x; // BottomSheetを閉じる res.dismiss(); });
BottomSheet内コンポーネント
handleQrCodeResult(resultString: string) { // QRが読み込めた時の処理。サービスのSubjectプロパティに値を流す ≪DI Class≫.scanSuccess.next(resultString); }
スクリプト内で特に指定しない限り、BottomSheetはEscキーなり、BottomSheet外をClickするなりしないと閉じないので
値が読み込めた段階で、bottomsheetのdismiss()
を使用して用がすんだら閉じてあげるのが良いかと思います。
bottomsheetのafterDismissed().subscribe()
で、BottomSheetが閉じた時を引っ掛けれるので
BottomSheet閉じた際に何か処理をしたい場合は、そいつを使うと楽にいろいろできそうです。
これで、親ComponentとBottomSheetのComponentでデータのやり取りが可能になりました。
結果
冒頭のGifの通り、QR/バーコードを使用したInputコントロールが作成できました。
おわりに
ソフトウェアキーボードみたいな、フォーカスあてると下からニュッと入力インターフェースが出てくるコントロールを作りたいという思いでBottomSheetを使用しました。
今回はQR/バーコードの読み取りで使用しましたが
Canvasあたりを使用すれば、手書きの入力コントロールも、OSのインターフェースっぽく表現できるかもしれませんね。
今回作成したものは、下記リポジトリで管理しています。
サンプルで作ったもののごった煮ですがご容赦ください。
バーコードとQRの生成は下記のサイトを使用しました。