Preface:
大約今年9月,我加入了一個網路服務產品的爆肝開發行列,負責的項目是網站前後端持續整合。

系統其實是採用Java EE來設計,針對前端一切都只是用很枯燥的JSP來呈現,看到如此困苦的開發,我心想GG惹,還是趕快洗洗睡,好家在 Angular.js 已經流行有好一段時間了,把所有功能需求列成表,開會討論後就把現狀JSP改用REST API形式來做,到現在已經讓我流了三十加侖的感動眼淚。

發了點牢騷,結論就是: Angular 能吃,還沒吃趕快去吃。

架構

如果網頁用Angular.js來設計了話,通常會用 Angular Router 來設計每個頁面,每個頁面幾乎都是Ajax請求來刷頁面,所以只要讀取 首頁 就行了,其他分頁、流程頁面都是靠ajax加載,這裡可以支援 pushState Ajax。

即時反應程度

Angular其實在載入的時候,已經可以針對每個元素做即時更新,你可用不著在屬性裡面寫一大堆有的沒的監聽屬性

<input name="search" onkeypress="doSomething(this)" sid="a1"/>  

其實如果你稍微看了一下 Angular Beginner's Guide 這類的文件,你會發現在程式控制器有個 $scope ,它本身就可以對變數做監聽、即時修改,別小看它,我會在下面繼續說明它的好處。

你可以看見假裝的登入如何用angular呈現: login.html

<form name="myForm" ng-controller="app">  
    <input name="myName" ng-modal="name" ng-value="name"/>
    <button ng-click="login()" ng-disabled="myForm.$invaild" required>Send to do something...</button>
    <p>{{status}}</p>
</form>  

app.js

app.controller('app',function($scope){  
    $scope.name = "Enter your nickname to login";
    $scope.status = "You are not logged in, please login";

    $scope.login = function(){
        let data = { name: $scope.name }
        $http.post("/login",data)
            .then(function(){ $scope.status="You have successfully logged in!"; })
            .catch(function(){ $scope.status="Login failed! Please check your nickname."; });
    }
});

你可以看見上述針對 html 表單,可以直接檢查是否輸入完畢,且可以透過 ng-model 和controller中的 $scope.name 綁定,在 ng-click 後,就可以直接對 controller 中的 $scope.login 呼叫,進行登入。

REST API 怎麼看?

上面你可以看到那個登入的範例,我用了 $http 來呼叫REST API, 不過要注意的是,你需要匯入這個模組,而我上述範例沒有匯入,你可以參考 ANGULAR DOCS - $HTTP ,上述皆可使用 GET, POST, PUT, DELETE。

除了 $http 方法以外,它採用Promise 的方式,所以出現了 then,catch ,詳情可以參考 MDN - Promise ,我在他回傳訊息時做了 $scope.status = "xxx" 來指定登入狀態給前端看,也就是說,登入後便能馬上知道結果,很方便。

少了什麼問題,常用方法?

上述你看到 $http 在指定回傳訊息 $scope.status = "xxx" 的時候,它正是使用callback,這可是會造成資料被刷掉,可是它並沒有。

在Angular中,已經預先寫好範圍控制的程式了,所以只要在 $scope 的作用域中,沒有人可以動你的程式碼。

資料處理的好處

說到這,這可是幫了我很大的忙,假設我要處理 F = (x,y) 2維不知道有多少陣列、Object物件資料的東西,又要能做 input 可以即時輸入,這可幫了大忙。

你只需要用 ng-repeat, 並且在重複過程中,指定 ng-model 是 foreach 的 key 就行了,超簡單。

我給個累死人的demo圖:

看吧,輕鬆解決,你還有時間多寫些 filter 工具。

ng-repeat 可以給你進化

看到ng-repeat,想要一個可以在 repeat 執行完後執行一個事件,也是可以自己寫,這時候就能自創一個 html 屬性:

<td ng-repeat="name in Users" on-finish-render="ngRepeatFinished"></td>  

我創了一個屬性叫 on-finish-render,你只要在 app.js 寫這段:

var module = angular.module('testApp', [])  
    .directive('onFinishRender', function ($timeout) {
    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            if (scope.$last === true) {
                $timeout(function () {
                    scope.$emit('ngRepeatFinished');
                });
            }
        }
    }
});

接著,只要在 controller 裡面監聽,像這樣:

$scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) {
    doSomething();
});

就可以在執行 repeat 後監聽到事件。

模板支援程度

上述你看到的 {{ name }} 這類標籤,其實很多引擎都支援,像是 vue.js 就有了,不過不再此探討,這類標籤可以在裡面做一些簡單的判斷,比方說使用者尚未輸入數值之前,應該處於等待輸入狀態,這時候可以顯示些提示文字:

{{ name | "請輸入數值" }}

可以說是蠻完整的,而這個標籤也是$scope,所以可以即時回應新修改資料。

節省效率概述

自從資料可以很快速被監聽這點,其實就已經加快很多速度了,而且如果你們是自己去 themeforest 買模板,很多模板已經開始支援 Angualr 使用了,可以說是更簡單就能完成大部分的工作。

By the way

你有看到 $scope 只是針對該控制器做控制,但是如果想要跨控制器呢,別擔心,有個內建元素叫做 $rootScope,這個$rootScope 是全域性的,看下面,你就明白了。

app.controller("first",function($rootScope,$scope){  
   $rootScope.$emit("fitst_controller","first controller say hi!");
});

app.controller("second",function($rootScope,$scope){  
    $rootScope.$on("first_controller",function(event,string){
        $scope.message = string;
    });
});

Postscript:
我想想,其實該是時候可以探討一下關於軟體測試、優化部分了,其實在之前都不會特別注意,直到產品需要持續整合才知道。