[無瑕的前端-4] 番外篇

Angular、TypeScript實作前端MVC架構

前情提要

在[無暇的前端]終卷已完成了將屬性設定到簽呈component內的功能,也封裝了呼叫後端api的方法,但現在使用者有新的需求,就是在簽呈component被按下submit按鈕之後,必須要同時更新主畫面。

實做範例

這類型的需求其實很常見,就是事件通知的功能,實做事件大概就掌握幾個要點

  1. 雙方約定好事件的簽名
  2. 註冊處理事件的handler

在開始之前,我們先在ViewModel專案定義一個ApproveViewModel來模擬狀態的回傳範例。

  public class ApproveViewModel
    {
        public string ApproveEmpno { get; set; }

        public string ApproveState { get; set; }
    }

接著打開TypeLite.Net4.tt,將ApproveViewModel新增進去,可參考下方程式碼片段,然後按下存檔。

<# var ts = TypeScript.Definitions()
		.WithReference("Enums.ts")
		.ForLoadedAssemblies()
		.For<Hank.Chen.ViewModel.MemberViewModel>()
		.For<Hank.Chen.ViewModel.ApproveViewModel>();
#>

再來便進入正題了,第一個要點,事先溝通好方法的簽名,舉例來講,如果以webform觀念,要實做ButtonClick事件,實做的方法必須接收兩個參數,一個是sender,一個是event。而這裡的做法觀念完全一樣,只是簽名必須自己定義。

所以接下來就在approve資料夾新增一個approve.interface的檔案,因為簽名是叫用端和簽呈component兩者都必須遵守,因此可見範圍要提升,所有module的命名空間需要寫成Hank.Chen,$event是angular內建的物件,我們把要傳遞回去的內容封裝在$event裡面,請參考下列程式碼,我們註冊一個IUpdating的介面,用來約定之後我們要回傳的物件型別,approve是自訂的物件名稱,可為任意值,型別是ViewModel.ApproveViewModel。

module Hank.Chen {
    export interface IUpdating {
        (e: { $event: { approve: ViewModel.ApproveViewModel } }): void
    }
}

再來實做簽呈component的controller,我們需要在bindings屬性裡綁定一個回呼的事件,綁定事件的指示詞是&,所以設定如下所示,綁定一個onUpdate的事件。

  angular.module('Hank.Chen.Components')
        .component('approve', {
            templateUrl: "TypeScripts/Components/approve/approve.detail.html",
            controller: ApproveController,
            bindings: {
                docno: '=',
                onUpdate: '&'
            }
        });

接著在使使用者按下submit後,需要呼叫綁定進來的方法,因為綁定的屬性是注入進來的,所以必需先在controller裡定義,否則會出現undefind,連編譯都不會過, 定義好onUpdate並且宣告他的方法簽名是IUpdating。

   onUpdate: IUpdating;

這個範例是宣告一個ApproveViewModel的物件,實務上當然不會寫死,然後將它封裝到$event裡,因為剛剛已經有宣告IUpdate的介面,因此可以知道$event裡有一個屬性叫做approve,設定好approve的值後,就可以透過綁定的事件回傳回去。

 Submit() {
            let value: ViewModel.ApproveViewModel = {
                ApproveEmpno: "00037313",
                ApproveState: "已核決"
            }

            this.onUpdate({ $event: { approve: value } });
        }

完整的approve程式碼如下所示

module Hank.Chen.Components {

    export class ApproveController {
        onUpdate: IUpdating;

        constructor(
        ) {

        }

        Submit() {
            let value: ViewModel.ApproveViewModel = {
                ApproveEmpno: "00037313",
                ApproveState: "已核決"
            }

            this.onUpdate({ $event: { approve: value } });
        }
    }

    angular.module('Hank.Chen.Components')
        .component('approve', {
            templateUrl: "TypeScripts/Components/approve/approve.detail.html",
            controller: ApproveController,
            bindings: {
                docno: '=',
                onUpdate: '&'
            }
        });
}

再來修改approve.detail的頁面,單純新增一個按鈕驗證功能就好。

<span>單據編號: {{$ctrl.docno}}</span>

<button ng-click="$ctrl.Submit()">核決</button>

到這裡元件就已經完成了,接下來便是頁面要如何使用這個功能,先定義controller接收此事件的方法,方法命稱update可以隨意定,但要宣告他的簽名是IUpdating,然後參數是{$event},請參考下列程式片段。

   update: IUpdating = ({$event}) =>{
            console.log($event.approve.ApproveState);
        }

 再來就是在approve的tag上新增on-update屬性,這裡一定要強調,如果設定成onUpdate,程式是不會動的,這裡不可使用駝峰式命名,必須使用-符號切開。接著把剛剛定義好的方法指派進去,並且設定好參數就完成了,請參考下列程式碼片段。

 <approve docno="MemberCtrl.member.Name" on-update="MemberCtrl.update({$event})"></approve>

到這裡就全部實做完成嚕,只要簽呈component的submit按鈕被按下,主頁面就會收到通知,並且會獲得簽呈component所告知的訊息。

 

結論

在TypeScript的世界裡,有種主宰一切的快感,神說,你是什麼你就是什麼,只要有注入對應的物件,我們可以恣意發揮我們的神力召喚所有定義好的服務來幫助我們架構網站,相信大家從初卷一路做到番外篇應該會漸漸有這樣的感覺,那就一起來享受angular + typescript帶來的美好前端生活吧