はまったりひらめいたり…とか…

Angularや.NETやAzureやその他色々。

AngularでQR/バーコードを使用するInputコントロールを作る

12/1 修正しました。

はじめに

今回のお話は、下記バージョンでお送りします

AngularCLI : 7.0.4

↓みたいなコントロールを作成していきます。

f:id:TakasDev:20181123231755g:plain

f:id:TakasDev:20181123232143g:plain

テキストボックスがあり

フォーカスが当たった際に、ソフトウェアキーボードではなくQRを読み込むカメラが起動し

カメラでQRが読み込めた場合

フォーカスが当たっていたテキストボックスに、QRから読み取った値を投入する。

といった動作です。

QR/バーコード読み込み

以前の記事でQRコードを読み取るために、@zxing/ngx-scanner を使用しました。

今回は、そのライブラリからForkされた、@innotec/ngx-scanner を使用します。

@innotec/ngx-scanner - npm

npm install @innotec/ngx-scanner --save

@zxing/ngx-scannerの@Inputにはformatsが追加されており、CODE39等のバーコードのFormatを指定することで

バーコードのデータも読み込むことができるようになります。

Formatの指定は、@zxing/libraryEnumで管理されている、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コンポーネントを使用しました。

Angular Material

準備

まずは、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のインターフェースっぽく表現できるかもしれませんね。

今回作成したものは、下記リポジトリで管理しています。

サンプルで作ったもののごった煮ですがご容赦ください。

github.com

バーコードとQRの生成は下記のサイトを使用しました。

バーコード

barcode.tec-it.com

QR

m.qrqrq.com