[ASP.NET] TypeScript + AngularJs Controller 撰寫方式

介紹使用 TypeScript + AngularJs 於 ASP.NET MVC 整合的 Controller 撰寫方式

前言


在萬事俱備,只欠 Controller 的情況下,終於要開始寫第一支 TypeScript 版的 Angular Controller 了,恩...但其實也跟之前的沒有差異很多,讓我們繼續看下去。

 

TypeScript Angular Controller


首先,我一樣先定義了一個 module 名稱為 ExampleApp.Controllers,如下

module ExampleApp.Controllers {

}

 

接下來一樣建立一個 Class 名為 HelloWorldCtrl,在此的命名建議是以 {檔案名稱} 加上 Ctrl,類別名稱相似檔案名稱也等於檢視名稱,你看看這是不是很直覺!

module ExampleApp.Controllers {

    export class HelloWorldCtrl {


    }

}

 

現在我們要建立一個 IHelloWorldCtrlScope 介面作為定義 angular 注入的 scope 型別,蛤? 你問我為什麼要建? 用 TypeScript 就是要用強行型別啊!不然要幹嘛!

建立介面的同時,需要 extends ng.IScope,這樣才能夠在我們定義的介面中使用到原本 angular 所提供的介面方法,如下

module ExampleApp.Controllers {

    export interface IHelloWordCtrlScope extends ng.IScope {

    }

    export class HelloWorldCtrl {


    }

}

 

接著,在 IHelloWordCtrlScope 增加一個 message 變數定義作為等等測試需用的變數。

而在 HelloWorldCtrl 類別中呢,先建立兩個靜態變數分別為 $name 與 $inject ,$inject 我之前提到過,是用於注入所需要的模組以及防止在 bundle 情況下注入失效,那 $name 又是作何用呢? $name 是我額外定義用來代表這個 Controller 的名稱,當我們在註冊 Angular Controller 時,需要傳入 Controller 的 name 與對應的 ControllerConstructor,像下面這樣

angular.module("ExampleApp").controller("MyCtrl", MyCtrl);

但是如果是依照上面這種寫法,如 Controller  Name 有異動的時候就需要去註冊的地方更改,為了避免這種散落各地的情況,我則改在將 name 放置於相同 Class 中控管,如下

module ExampleApp.Controllers {

    export interface IHelloWordCtrlScope extends ng.IScope {
        message: string;
    }


    export class HelloWorldCtrl {
        static $name = "HelloWorldCtrl";
        static $inject = ["$scope"];

    }

}

接下來繼續完成  constructor 的建立,透過在 constructor 傳入的 $scope 指定型別為 IHelloWorldCtrlScope 並指派 message 值,在這個撰寫過程中,你都可以使用到強行別以及 Intellisense,如下

module ExampleApp.Controllers {

    export interface IHelloWordCtrlScope extends ng.IScope {
        message: string;
    }


    export class HelloWorldCtrl {
        static $name = "HelloWorldCtrl";
        static $inject = ["$scope"];

        private scope: IHelloWordCtrlScope;

        constructor(
            $scope: IHelloWordCtrlScope) {

            this.scope = $scope;

            this.scope.message = "Hello World!!!!";
        }

    }

}

 

最後最後,必須要將你所撰寫好的 Controller 註冊到 module 內,此時就需要呼叫在 App.ts 裡面的 RgeisterController 方法,如下

module ExampleApp.Controllers {

    export interface IHelloWordCtrlScope extends ng.IScope {
        message: string;
    }


    export class HelloWorldCtrl {
        static $name = "HelloWorldCtrl";
        static $inject = ["$scope"];

        private scope: IHelloWordCtrlScope;

        constructor(
            $scope: IHelloWordCtrlScope) {

            this.scope = $scope;

            this.scope.message = "Hello World!!!!";
        }

    }

}

ExampleApp.RegisterAngular.RegisterController(
    ExampleApp.Controllers.HelloWorldCtrl.$name,
    ExampleApp.Controllers.HelloWorldCtrl);

在 HelloWorld 檢視頁面,增加 ng-controller 屬性,如下

<h2>HelloWorld Demo</h2>

<div ng-controller="HelloWorldCtrl">
    <span ng-bind="message"></span>
</div>

執行後結果顯示如下

 

番外篇,加入 ViewModel 與 Event


在看完以上的基本操作後,我們可以增加更多的變化,例如在實際針對 Document 上的元素修改值時建立一個 ViewModel 處理,又或者針對 Document 上的按鈕按下時要增加對應的事件處理。

首先增加一個 HelloWorld.ViewModel.ts 檔案,內容如下

module ExampleApp.Controllers {

    export class HelloWorldViewModel {
        public Message: string;
    }

}

接著調整一下原本的 IHelloWordCtrlScope,定義 model 使用 HelloWorldViewModel 並增加一個點擊事件,如下

module ExampleApp.Controllers {

    export interface IHelloWordCtrlScope extends ng.IScope {
        model: Models.HelloWorldViewModel;
        
        SayHello(): void;
    }

    export class HelloWorldCtrl {
        static $name = "HelloWorldCtrl";
        static $inject = ["$scope"];

        private scope: IHelloWordCtrlScope;

        constructor(
            $scope: IHelloWordCtrlScope) {

            this.scope = $scope;

            this.scope.SayHello = this.SayHello;

            var model = new Models.HelloWorldViewModel;
            model.Message = "Hello World!!!";

            this.scope.model = model;
        }

        public SayHello(): void {
            var scope: IHelloWordCtrlScope = <any>this;
            scope.model.Message = "Hello Arvin!!!";
        }

    }

}

ExampleApp.RegisterAngular.RegisterController(
    ExampleApp.Controllers.HelloWorldCtrl.$name,
    ExampleApp.Controllers.HelloWorldCtrl);

HelloWorld.cshtml 檢視稍微調整如下

<h2>HelloWorld Demo</h2>

<div ng-controller="HelloWorldCtrl">
    <span ng-bind="model.Message"></span><br />
    <input type="button" value="Say Hello" ng-click="SayHello()" />
</div>

執行後就會產生以下結果

這邊要注意一下,你看到我做了一個 var scope: IHelloWordCtrlScope = <any>this; 的動作,其原因在於當進入 SayHello() 時,this 返回的值會是 scope 本身不是 HelloWorldCtrl。

如果在此時在 TypeScript 是寫以下這樣

public SayHello(): void {
    this.scope.model.Message = "Hello Arvin!!!";
}

就會發生操作 this.scope 是 undefined 的錯誤,所以才會額外在做這個動作將 this 直接變成 IHelloWordCtrlScope 進行操作,針對這個問題目前還未找到更佳解,希望如果有經驗的前輩可以指點一下。

 

結語


以上就是 Controller 的撰寫方式,感覺短短一篇結果打了好久....Orz

 

接下一篇 TypeScript + AngularJs Directive 撰寫方式

 

 


以上文章敘述如有錯誤及觀念不正確,請不吝嗇指教
如有侵權內容也請您與我反應~謝謝您 :)