Angular、TypeScript實作前端MVC架構
前言
承接之前的系列文,這裡主要整理自己在實作過程中遇到的一些問題,以免之後浪費寶貴的時間。下列為簡單描述的幾個情境讓我困惑之處。
注入到Controller的物件是如何對應
注入只看順序性,名稱甚至可以完全不同,以上方例子而言,Memer在注入的時候是大寫,但是在constructor內是小寫的member。當然,也可以取完全不一樣的名字,因為controller是完全針對view在設計,因此,宣告一個適當的名字會有助於對程式碼的理解。
另外,member後方的:ViewModel.MemberViewMoel是在宣告型別,基本上,在TypeScript世界裡,程式設計師就是神,神主宰一切,所以神說它是甚麼型別,它就會是甚麼型別。但是說穿了,這只是在編譯時期TypeScript會依照你宣稱的型別來幫你做檢查而已,所以到了執行階段,TypeScript發現這個物件的型別跟你宣告的不一樣,而剛好又對物件不存在的屬性做了讀取的動作,程式還是會爆炸的,這點要特別注意。
Controller呼叫封裝$http成Service的簡單範例
在angular的世界裡,想要與後端的WebApi作互動,一般來說都會使用$http這個物件,所以把它封裝在Service裡面會是一個不錯的設計方式。
以下就是簡單的Service設計,提供一個GetMember的方法,並且接受一個參數model,型別為ViewModel.MemberViewModel。
export class MemberService {
GetMember(model:ViewModel.MemberViewModel) {
var url = 'http://localhost/api/member';
return this.$http.post<void>(url,model);
}
}
接下來處理controller,把這個定義好的服務注入進來,然後在controller定義一個方法來呼叫這個Service。這樣做的好處就是,其他程式人員想要呼叫同一個WebApi時,使用這個Service就會得到intellisense的好處,也不需要知道太多實作的細節,只需要給予適當的參數即可。
export class MemberController {
static $inject = ['MemberService'];
constructor(
memberService: MemberService
) {
}
Submit(): void {
let model :ViewModel.MemberViewModel ={
Id:"1234"
}
memberService.GetMember(model);
}
Html如何引用Controller的資料
Html跟Controller要關聯上是靠angular.ui.route來設定,可參考下方設定。
function MemberControllerRoute($stateProvider: angular.ui.IStateProvider) {
$stateProvider
.state('member',
{
url: '/member',
templateUrl: 'TypeScripts/Controllers/MemberLogin/member.base.html',
controller: 'BaseController',
controllerAs: 'BaseCtrl',
resolve: {
}
})
}
透過templateUrl取得html頁面,然後透過controller屬性指定controller,這裡的名稱需要完全跟angular.module裡設定的controller名稱匹配,否則會出現錯誤。但有時controller的名稱太長,所以可以使用controllerAs的屬性來設定縮寫,而這個縮寫將會成為html頁面上controller的參考,html頁面可透過這個參考來取得controller內的資訊,以及呼叫定義的方法,可參考以下範例。
controller只定義一個Id的屬性供存取之用,下方的angular.module('Hank.Controllers')....則是將BaseController註冊到angular的module,第一個參數是Key(字串),必須要跟上方route設定的controller名稱匹配,第二個參數是實際型別。
module Hank.Controllers {
export class BaseController {
Id:string
}
}
angular.module('Hank.Controllers')
.controller('BaseController', BaseController);
}
Html的部分就可以透過route設定的簡稱BaseCtrl當作參考,直接讀取controller內的資訊。
<div >
{{BaseCtrl.Id}}
</div>
常見問題
執行typeScript為何會出現下列畫面?
偵錯時請按ctrl+F5,並且不要直接在html頁面上按,不然它會直接去讀這個頁面,所以造成angular的東西會沒被載入而出現這個畫面。
angular.ui.route套件,巢狀的state跑不出來?
如果templateUrl的名稱一樣的話,就會導致畫面跑不出來。其實,也不應該有這兩個url需要一樣的需求,但這問題算是比較雷的,它沒有錯誤訊息,就單純畫面跑不出來而已,所以要多加注意。
結論
寫程式很吃筆記,不管是甚麼程式語言都有滿山滿谷的坑,就算自己不跳,別人也會挖給你跳。所以沒辦法避免不跳新坑,但卻有辦法一樣的雷不去踩第二次,而作筆記或寫部落格真的是一個很棒的方式,大家共勉之。