0%

[Angular]技巧系列-BarcodeListener

前情提要

筆者在工作環境中,有一個小週邊系統是給分行人員使用,其中有一段是需要透過Barcode Scanner掃描其帳單中的條碼,作為Form表單送出時的一個欄位,筆者看同事一開始的做法是在畫面上放一個Input,其游標須Focus在該Input上,然後按下Barcode Scanner去掃描條碼。

上述情境會延伸一些問題,使用者將游標移至其他表單元件或者系統上會有Toast訊息,使用者可能會點擊其Toast訊息關閉,上述零零總總情境後,若要掃描條碼,必須得將游標自動Focus回條碼所屬的Input上,極為困難,要寫很多code去做到;若沒有自動將游標Focus回對應的Input上,使用者會覺得困擾,每次掃描前都要移動滑鼠,將游標移回條碼所屬的Input上,此篇內容就是要解決上述遇到的問題。

筆者這邊的開發環境如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
npm --version
6.14.11

node --version
v10.24.0

ng --version
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/

Angular CLI: 11.2.15
Node: 10.24.0
OS: win32 x64

Angular: 11.2.14
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router
Ivy Workspace: Yes

Package Version
---------------------------------------------------------
@angular-devkit/architect 0.1102.15
@angular-devkit/build-angular 0.1102.15
@angular-devkit/core 11.2.15
@angular-devkit/schematics 11.2.15
@angular/cli 11.2.15
@schematics/angular 11.2.15
@schematics/update 0.1102.15
rxjs 6.6.7
typescript 4.1.6

內容

筆者第一份工作就是做MES相關軟體,其客戶環境都在工廠中,很常接觸到使用Barcode Scanner的環境,其相對應的系統上的很多資料是從Barcode Scanner讀取取得,那時就有一個觀念是監聽Keyboard事件,因Barcode Scanner的特性,分為兩種

  • 一種是Prefix, Suffix特殊符號的方式判斷開始、結束,會有一個特殊的Prefix Code,結尾都會帶Enter鍵,就知道是從Barcode Scanner輸入值r
  • 一種是Time-based的方式判斷,畢竟人工輸入無法這麼快速,Barcode Scanner掃描卻非常快速,利用這個特點,我們可以監聽全域的Keypress事件,並且設定timeout時間非常短暫,時間到將暫存的chars往外拋並清空,再回到初始狀態

第一種的有幾個現成包好的angular套件可以使用,但筆者的情境可能無法適用

  • 一是無法對於每個分行用甚麼barcode scanner做一些限制
  • 二來不太可能一個新的Barcode Scanner就得幫它設定好PrefixSuffix

筆者選擇第二種Time-based的方式判斷,跟著筆者實作測試看看吧。

建立Angular專案

1
2
3
ng new demo-code
cd demo-code
code .

撰寫Barcode監聽程式

建立好Angular專案,實作其程式,為demo,就直接寫在app.component.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import { Component, HostListener, OnDestroy, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit, OnDestroy {
title = 'demo-barcode';
pressed = false;
chars: any[] = [];
frmDemo: FormGroup;
constructor(private builder: FormBuilder) {}
ngOnDestroy(): void {}
ngOnInit(): void {
this.frmDemo = this.builder.group({
barcode: [''],
});
}

@HostListener('document:keypress', ['$event'])
handleKeyboardEvent(e: KeyboardEvent) {
if (e.which >= 48 && e.which <= 57) {
this.chars.push(String.fromCharCode(e.which));
}
if (this.pressed == false) {
setTimeout(() => {
if (this.chars.length >= 10) {
var barcode = this.chars.join('');
this.frmDemo.get('barcode').setValue(barcode);
}
this.chars = [];
this.pressed = false;
}, 500);
}
this.pressed = true;
}
}
1
2
3
<pre>
{{ frmDemo.value | json }}
</pre>

實際執行

實作完程式,執行看看吧,要準備好Barcode Scanner及各式各樣的條碼

1
npm start

在瀏覽器中開啟其對應網址,http://localhost:4200,實作程式畫面中印出Form Value即可知道有無掃描監聽成功,實際效果如下

1
2
3
{
"barcode": "0116100001088"
}

結論

使用Time-based的特性,搭配全域Keypress事件取得Barcode Scanner掃描出來的值變得如此簡單,不用再為FocusFocus去而煩惱,不過這個只是demo版本,實際應用時,可能也要加一些防呆機制,若條碼有規則,在timeout function中做一個實際的驗證,這篇就到這邊了,希望有幫助到各位。

參考