Angular RxJS JavaScript

使用 RxJS:range 完成信用卡有效日期選項

許智庭 Tim Hsu 2022/03/04 14:31:06
1201

layout

要呈現的畫面如下圖,

credit card valid date

切版內容如下:

HTML

<label>信用卡有效期限:</label>
<div class="creditCard">
  <div class="drop">
    <div class="dropOption">
      <span>有效月份</span>
    </div>

    <ul class="dropdown">
      <li>選項 1</li>
      <li>選項 2</li>
      <li>選項 3</li>
      <li>選項 4</li>
      <li>選項 5</li>
      <li>選項 6</li>
      <li>選項 7</li>
      <li>選項 8</li>
    </ul>
  </div>
  <span>/</span>

  <div class="drop">
    <div class="dropOption">
      <span>有效年份 </span>
    </div>

    <ul class="dropdown">
      <li>選項 1</li>
      <li>選項 2</li>
      <li>選項 3</li>
      <li>選項 4</li>
      <li>選項 5</li>
      <li>選項 6</li>
      <li>選項 7</li>
      <li>選項 8</li>
    </ul>
  </div>
</div>

 

SCSS

label {
  font-size: 24px;
  padding: 0.5rem;
  font-weight: bold;
  color: #333;
  border-left: orange 5px solid;
  margin-bottom: 0;
}
.creditCard {
  display: flex;
  align-items: center;
  padding-top: 1rem;
  > span {
    margin: 0 1rem;
  }
  .drop {
    position: relative;
    display: block;
    width: 130px;
    // margin: 0 0 10px;
    &:hover {
      .dropOption {
        display: block;
      }
    }
    &:hover {
      .dropdown {
        display: block;
      }
    }
    &:hover {
      .dropdown.close {
        display: none;
      }
    }
    .dropOption {
      position: relative;
      width: auto;
      color: #666;
      font-size: 20px;
      background-color: #fff;
      padding: 10px;
      border: 1px solid #888;
      border-radius: 5px;
      box-sizing: border-box;
      cursor: pointer;
      &::after {
        content: "";
        position: absolute;
        top: 20px;
        right: 12px;
        border-width: 8px 6px;
        border-style: solid;
        border-color: #999 transparent transparent transparent;
      }
    }
    .dropdown {
      display: none;
      width: 100%;
      max-height: 350px;
      position: absolute;
      color: #333;
      padding: 0;
      margin: 0;
      background-color: #f9f9f9;
      box-shadow: 0px 2px 3px 0px #ccc;
      border-radius: 6px;
      box-sizing: border-box;
      overflow: auto;
      z-index: 10;
      > li {
        display: block;
        color: #000;
        padding: 12px;
        font-size: 20px;
        margin: 0 10px;
        cursor: pointer;
        &:first-child {
          margin: 10px;
        }
        &:last-child {
          margin-bottom: 10px;
        }
        &:hover {
          background-color: #eee;
          border-radius: 6px;
        }
      }
      &::-webkit-scrollbar {
        width: 15px;
      }
      &::-webkit-scrollbar-track {
        background-color: #eee;
        border-radius: 6px;
      }
      &::-webkit-scrollbar-thumb {
        background-color: #888;
        border-radius: 15px;
      }
      &::-webkit-scrollbar-button {
        background-color: #f9f9f9;
      }
    }
  }
}

使用 RxJS: range 來完成功能

range 顧名思義就是依照一個範圍內的數列資料建立 Observable,包含兩個參數:
start: 從哪個數值開始
count: 建立多少個數值的數列

簡易範例:

import { range } from "rxjs";

range(3, 4).subscribe((data) => console.log(`range 範例: ${data}`));
// range 範例: 3
// range 範例: 4
// range 範例: 5
// range 範例: 6

tip: range 參數只能放 number。

透過以上範例我可以自訂一個數列的範圍,那月份跟年份就有解了,因為都有範圍:

  1. 月份:1~12 月份,並且我在個位數前面加個 0 ,使資料看起來有一致性。
  2. 年份:信用卡有效期限基本上在 3 到 5 年左右,所以也不會無限上綱。

想法是我今天只要訂出月份 1 到 12 月,並建立一個陣列把 1 到 12 月份去模板上跑迴圈,並且使用 click 事件把選到的值重新渲染在畫面上即可。然後我就可以這樣做:

程式碼不長也很簡單。

取得年份與月份

透過 range 建立年份與月份的陣列資料,並透過 click 事件把選到的值渲染在模板上,細節寫在註解中。


app.component.ts

ngOnInit(): void {
  this.validMonth(); //務必呼叫方法,才能跑出陣列資料
}

//*有效月份
creditMonth: string[] = [];
monthValue: string;

validMonth() {
  range(1, 12)
    .pipe(
      map((x) => {
        return ('0' + x.toString()).slice(-2);
        //因為我只要取最後兩位數,所以要先轉成字串再去處理
      })
    )
    .subscribe((res) => {
      this.creditMonth.push(res); //將每一月份依序放到陣列中
    });
}

checkMonth(month: string) {
  this.monthValue = month; //選到的月份顯示於下拉選單主選擇框內
}

 

app.component.html
修改模板語法,加上 ngFor 指令以及 click 方法。

<label>信用卡有效期限:</label>
<div class="creditCard">
  <div class="drop">
    <div class="dropOption">
      <span>{{ monthValue ? monthValue : "有效月份" }}</span>
    </div>

    <ul class="dropdown">
      <ng-container *ngFor="let item of creditMonth">
        <li (click)="checkMonth(item)">{{ item }}</li>
      </ng-container>
    </ul>
  </div>
  <span>/</span>

  <div class="drop">
    <div class="dropOption">
      <span>{{ yearValue ? yearValue : "有效年份" }} </span>
    </div>

    <ul class="dropdown">
      <ng-container *ngFor="let item of creditYear">
        <li (click)="checkYear(item)">{{ item }}</li>
      </ng-container>
    </ul>
  </div>
</div>

 

小結

善用 RxJS 的 range 事件可以建立有範圍的資料,這次的應用就覺得很有意思,不僅好管理也提升效率,非常推薦喔!

DEMO

連結:https://stackblitz.com/edit/angular-ivy-ppxopm?embed=1&file=src/app/app.component.ts

參考資料

許智庭 Tim Hsu