《用AngularJS開發下一代Web應用》讀書筆記②:AngularJS應用骨架

調用Angular

  • 使用Angular首先要做兩件事:
    1. 加載angular.js庫
    2. 使用ng-app指令告訴Angular應該管理DOM中哪一部分
  • 鑒于天朝在網絡世界中修筑了萬里長城,推薦使用國內的CDN緩存代碼庫(cdn.css.net網站中提供各種CDN的搜索)
<script 
    src="https://cdn.css.net/files/angular.all/1.2.18/angular-all.min.js">
</script>
  • ng-app指令告訴Angular應該蓋頁面的哪一塊,即Angular的模塊。
<!-- 如果是構建純Angular應用,可以寫在`<html>`元素中 -->
<html ng-app>
    ···
</html>

或者

<html>
    <!-- 如果應用已經使用了類似JSP、Rails的其他技術,也可以寫在要管理的DOM元素中 -->
    <div  ng-app>
        ···
    </div>
</html>

Model View Controller

  • 第一章提到Angular框架是通過MVC風格來設計web應用的,使之具有很強的靈活性。MVC包括:
    • 模型(Model)用來容納數據,代表應用當前的狀態;
    • 視圖(View)用來展示數據;
    • 控制器(Controller)來管理模型和視圖之間的關系;
  • 我們可以通過$scope對象的屬性來創建數據模型,可以只用基本數據類型來存儲數據,也可以用一個JavaScript類來存儲數據。
  • 定義Angular的正確方式應該是,先定義Angular模塊,然后把控制器定義為模塊的一個方法。 通過模塊機制可以幫助我們把代碼從全局命名空間中隔離開來。
<!doctype html>
<!-- 通過ng-app設置Angular管理的范圍  -->
<html ng-app='myApp'>
    <head>
        <!-- 引入Angular的文件 -->
        <script src="https://cdn.css.net/files/angular.all/1.2.18/angular-all.min.js"></script>
    </head>
    <!-- 通過ng-controller聲明控制器-->
    <body ng-controller='TextController'>
        <!-- 通過雙花括號定義雙向綁定的數據 -->
        <p>{{hello}} {{TextObj.message}}!</p>
        <script type="text/javascript">
            //通過angular.module()方法聲明模塊,第一個參數是模塊名,第二個參數是需要依賴的模塊(這里是空數組)
            var myAppModule = angular.module('myApp',[]);
            //通過module.controller()方法聲明控制器,參數是控制器方法的具體實現
            myAppModule.controller('TextController',function($scope){
                //變量
                var hello = 'hello';
                //對象
                var TextObj = {
                    message : "World"   
                };  
                //賦值給$scope
                $scope.TextObj = TextObj;
                $scope.hello = hello;
            });
        </script>
    </body>
</html>

模板和數據綁定

<div ng-repeat='item in items'>
    <span>{{item.title}}</span>
</div>
  • 如上代碼所示,Angular的模板是HTML片段,而items數組是數據模型,通過ng-repeat指令Angular框架會遍歷items數組的每一項,并給<div>元素生成一份拷貝,延展出HTML內容。
  • 在實際應用中,items數組往往是通過請求服務端的數據結果。
  • 一個Angular應用的基本運作流程如下:
    ① 用戶請求Angualr應用起始頁;
    ② 瀏覽器向服務器發起HTTP連接,加載起始頁.html頁面(頁面中包含模板);
    ③ 開始解析頁面,加載Angualr框架到頁面,DOM構建完畢后開始查找ng-app指令,根據這個指令來定義Angular的模板邊界;
    ④ Angular框架的初始化工作:注冊監聽器、執行一些DOM操作、從服務器獲取初始化數據。初始化工作完畢后,模板被轉換成DOM視圖;
    ⑤ 連接到服務器,加載需要展示給用戶看的其他數據;
顯示文本
  • 將JS變量的文本值顯示到UI中,除了使用雙花括號之外,還可以使用'ng-bind'指令。兩種形式的輸出內容是相同的。
  • 使用使用雙花括號的方式,可以讓模板代碼閱讀起來更自然,但有一個問題,就是在Angular使用數據替換這些花括號之前,未被渲染好的模板可能會被用戶看到。造成這種現象的原因是,瀏覽器需要先加載并渲染HTML頁面,Angular才開始初始化工作。
表單輸入
  • 對所有標準的表單元素,Angualr框架都支持,并且操作起來非常方便,只需要將ng-model屬性聲明到要操作的元素即可。
  • 案例:Angular操作復選框
<from ng-controller='SomeController'>
    <!-- 通過ng-model將控件值綁定到youCheckedIt變量中 -->
    <input type="checkbox" ng-model='youCheckedIt' />
</from>
  • 我們還可以通過ng-change指令監聽控件的改變
  • 案例:自動獲取十倍的數字計算控件
<from ng-controller='StartUpController'>
    Starting: <input type="text" ng-model='funding.startingEstimate' />
    Remomendation:{{funding.needed}}
</from>
<script type="text/javascript">
    var myAppModule = angular.module('myApp',[]);
    myAppModule.controller('StartUpController',function($scope){
        $scope.funding = {startingEstimate : 0};
        $scope.computeNeeded = function(){
            $scope.funding.needed = $scope.funding.startingEstimate * 10;
        };
    });
</script>
  • ng-change指令只能監聽頁面控件的變化,如果是接收到服務器返回的信息,需要刷新數據模型,該怎么辦呢?
  • $watch()函數用來監聽一個表達式,當表達式發送改變時會調用一個回調函數
myAppModule.controller('StartUpController',function($scope){
    $scope.funding = {startingEstimate : 0};
    $scope.computeNeeded = function(){
        $scope.funding.needed = $scope.funding.startingEstimate * 10;
    };
    //添加$watch
    $scope.watch('funding.startingEstimate',computeNeeded);
});
  • Angular支持通過ng-submit指令監聽表單提交動作。
<from ng-controller='SomeController' ng-submit='requestFnding()'>
  ···
</from>
  • Angular提供一系列類似瀏覽器原生事件屬性的指令,比如ng-clickng-dbclick
淺談非入侵式JavaScript
  • 非入侵式JavaScript代碼主要可以從以下兩點來解讀:
    • JavaScript的兼容性問題,需要根據在不同瀏覽器編寫不同的代碼;
    • 不同類庫集成進來引發的全局命名沖突問題;
    • 不同的事件監聽器綁定數據結構和行為,讓代碼變得難以理解和維護,擴展性差;
  • 一開始我們會把事件處理器定義在元素上,然后為這些元素賦ID值,獲取元素的引用?;蛘?,也可以通過一個統一的處理器來管理這些事件,但大多數應用,最后還是會把代碼弄得亂七八糟。
  • 而Angular是通過ng-eventhandler="expression"來處理,這里的eventhandler可以被替換成click、mousedown等原生的JS事件。
  • 雖然也還是將事件綁定通過元素屬性進行聲明,但是具有以下特點:
    • Angular幫助開發者屏蔽瀏覽器的差異性;
    • 通過Angular控制器的作用域范圍避免擾亂全局命名空間的秩序;
    • 沒有在任何地方引用DOM或者DOM事件,所有定位元素和處理事件監聽都在Angular內部完成;
    • 傳統的JavaScript程序的頁面邏輯和DOM是強耦合的,給單元測試增加了復雜性,而Angular則不會有這些問題;
列表、表格以及其他迭代類型
  • ng-repeat指令可以遍歷數據模型,并動態構建DOM節點,可算是Angular最常用的指令之一了。
  • 案例:學生花名冊系統
<!DOCTYPE html>
<!-- 1.通過ng-app設置Angular管理的范圍 -->
<html ng-app='myApp'>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <!-- 2.引入Angular的文件 -->
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
    <body>
        <ul ng-controller='StudentListController'>
            <li ng-repeat='student in students'>
                <a href="javascript:void(0);">{{$index+1}}.{{student.name}}</a>
            </li>
        </ul>
        <button ng-click='addStudent()'>Add</button>
        <script type="text/javascript">
            //偽數據
            var students = [
                {name : 'Mary Contrary',id:1},
                {name : 'Jack Spart',id:2},
                {name : 'Jill Hill',id:3},
                {name : 'William Liang',id:4},
                {name : 'Yoki Chen',id:5}
            ];
            var myApp = angular.module('myApp',[]);
            myApp.controller('StudentListController',function($scope){
                $scope.students = students;
                $scope.addStudent = function(){
                    $scope.students.splice(1,0,{name:'test',id:6});
                }
            });
        </script>
    </body>
</html>
  • ng-repeat指令中還可以通過$index返回當前引用元素的序號,通過$first、$middle以及$last返回布爾值,判斷當前元素是否為首個元素、是否為中間元素以及末尾元素。
顯示和隱藏
  • Angualr通過ng-showng-hide指令顯示和隱藏元素,當ng-show在表達式為true時顯示元素,false時隱藏元素,ng-hide則恰好相反。
<!DOCTYPE html>
<!-- 1.通過ng-app設置Angular管理的范圍 -->
<html ng-app='myApp'>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <!-- 2.引入Angular的文件 -->
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
    <body>
        <div ng-controller='SwichMenuController'>
            <button ng-click='toggleMenu()'>Add</button>    
            <ul ng-show='menuState.show'>
            </ul>   
        </div>
        <script type="text/javascript">
            var myApp = angular.module('myApp',[]);
            myApp.controller('SwichMenuController',function($scope){
                $scope.menuState.show = false;
                $scope.toggleMenu = function(){
                    $scope.menuState.show = !$scope.menuState.show;
                }
            });
        </script>
    </body>
</html>
CSS類和樣式
  • Angular可以動態設置CSS類和樣式,通過雙花括號進行數據綁定。
  • 案例:動態修改顏色
<!DOCTYPE html>
<html ng-app='myApp'>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .menu-disabled-true{ color:gray }
        </style>
    </head>
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
    <body>
        <div ng-controller='StudentListController'>
            <ul>
                <li class="menu-disabled-{{isDisabled}}" ng-click='stun()'></li>
            </ul>   
        </div>
        <script type="text/javascript">
            var myApp = angular.module('myApp',[]);
            myApp.controller('SwichMenuController',function($scope){
                $scope.isDisabled = false;
                $scope.stun = function(){
                    $scope.isDisabled = true;
                }
            });
        </script>
    </body>
</html>
  • Angular框架同樣適用于內聯樣式,比如style="{{someexpression}}",這種方式具有很大的靈活性。
  • 除此之外,Angular框架還提供ng-classng-style指令,接受一個表達式。
  • 案例:通過ng-class顯示錯誤和警告信息
<!DOCTYPE html>
<html ng-app='myApp'>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
            .error{background-color: red;}
            .warrning{background-color: yellow;}
        </style>
    </head>
    <script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
    <body>
        <div ng-controller='HeaderController'>
            <div ng-class='{error:isError,warning:isWarning}'>
                {{messageText}}
            </div>
        </div>
        <button ng-click='showError()'>Simulate Error</button>
        <button ng-click='showWarning()'>Simulate Warning</button>
        <script type="text/javascript">
            var myApp = angular.module('myApp',[]);
            myApp.controller('HeaderController',function($scope){
                $scope.isError = false;
                $scope.isWarning = false;
                
                $scope.showError = function(){
                    $scope.messageText = 'This is an Error';
                    $scope.isError = true;
                    $scope.isWarning = false;
                };
                
                $scope.showWarning = function(){
                    $scope.messageText = 'This is an Warning';
                    $scope.isWarning = true;
                    $scope.isError = false;
                };
            });
        </script>
    </body>
</html>
反思src和href屬性
  • Angular通過ng-srcng-href指令動態設置超鏈接和圖片屬性
<img ng-src='/images/cats/{{favoriteCat}}'>
<a ng-href='/shop/category={{numberOfBalloons}}'>some text</a>
表達式
  • Angular在模板中使用表達式是為了在模板、業務邏輯和數據之間建立聯系,避免讓業務邏輯滲透到模板中。
  • angular的表達式可以進行簡單的數據運算(+、-、*、/、%),進行比較運算(==、!=、>、<、>=、<=),執行布爾邏輯(&&、||、!),以及位運算(^、&、|)。
  • 但是我們應該清晰地區分視圖和控制器之間的職責,盡量不要類似運算符的業務邏輯操作放到模板中。
  • 表達式是通過Angular內置的解析器執行的,但是不支持循環結構(for、while)、流程控制操作(if-else、throw)以及修改數據的操作符(++、--),請在控制器中執行或者通過指令執行。
區分UI和控制器和職責
  • 控制器有三種職責:
    • 為數據模型設置初始狀態;
    • 通過$scope對象把數據模型和函數暴露給函數;
    • 監視模型其余部分的變化,并采取相應的動作;
  • 為了讓控制器保持小巧和可管理的狀態,我們建議為視圖中的每一塊功能區域創建一個控制器。
  • Angular中把控制器綁定到DOM節點上主要有兩種方式:
    1. 在模板中通過ng-controller屬性聲明;
    2. 通過路由把控制器綁定到DOM模板片段;
  • 同時,開發者還可以創建嵌套的控制器,使它們可以通過繼承樹的結構來共享數據模型和函數,讓應用的代碼保持簡介,容易維護。
<!-- ChildController的$scope對象可以訪問ParentController的$scope對象上所有的屬性 -->
<div ng-controller='ParentController'>
    <div ng-controller='ChildController'></div>
</div>
利用$scope暴露模型數據
  • Angular利用向控制器傳遞$scope對象的機制,可以把模型數據暴露給視圖??梢园?scope當成一個上下文環境,而在這個環境中,數據模型的變化變得可以觀察,甚至還可以通過模板自身創建數據模型。
<!-- ① 可以直接在模板表達式中定義變量 -->
<button ng-click='count=3'>Set Count to Three</button>
<!-- ② 也可以通過構造器函數定義變量 -->
<div ng-controller='CountController'>
   <button ng-click='setCount()'>Set Count to Three</button>
</div>
<script type="text/javascript">
function CountController($scope){
   $scope.setCount = function(){
        $scope.count = 3;
   };
}
</script>
使用$watch監控數據模型的變化
  • $scope$watch函數可以實現,當數據模型發生變化時,及時得到通知。
  • 函數簽名:$watch(watchFn,watchAction,deepWatch)
  • watchFn是一個字符串,可以是Angular表達式或者對象名,它代表數據模型的當前值。值得注意的是,這個字符串所代表的對象會被輪訓檢查多次,所以務必要保證它不會產生其他的副作用。
  • watchAction是當數據模型發生變化時調用的函數或者表達式,其函數簽名是 function(newValue,oldValue.scope)。
  • deepWatch是個可選的boolean值,帶包是否檢查數據模型的每個屬性。如果想要監控數組中的元素,或者的對象中所有的屬性變化,可以使用這個參數。
  • 同時,$watch()執行后還會返回一個函數,當你不再需要接收變更通知時,可以執行這個返回的函數,以銷毀整個監聽器。
//監聽someProperty屬性值的變化
var dereg = $scope.$watch('someModel.someProperty',callbackOnChange());
dereg();    //銷毀
watch()中的性能注意事項
  • 實際上,Angular在實現watch()方法時,會把所有被監控的屬性都拷貝一份,然后拿來和當前的值進行比較,檢查是否有變化。
  • 這樣的運行機制會造成性能損耗,推薦通過一個Chrome調試插件(Batatrang)來檢測,看看那些數據綁定的操作比較昂貴。
  • 有兩種方式可以監控多個屬性或者對象:
    1. 通過“+”號連接這些屬性;

$scope.$watch('things.a+things.b',callMe(...));

2. 將要監控的屬性放到一個數組或者對象中,并將`deepWatch`參數設置成true;

$scope.$watch('things',callMe(...),true);



### 使用Module(模塊)組織依賴關系
- 在開發中經常會遇到的難題是 __如何把代碼組織在合理的功能范圍內?__ 
- MVC的處理方式,是將控制器看做一個解耦的方法,把正確的數據模型暴露給視圖模板。但其他用來支撐我們應用的代碼該怎么辦?要把它們寫在控制器函數里面嗎?這么做會使控制器變成一個垃圾場,使得控制器的代碼變得難以理解,無法維護。
- `模塊機制`解決了上訴問題,它把那些負責提供特殊服務的代碼稱為`依賴服務`,它專門來組織應用中各個功能區塊的依賴關系,甚至可以自動進行依賴注入。
- 案例:當控制器需要從服務器獲取商品列表時,通常情況我們會把相關的處理通通寫到一個方法中

function ItemsViewController($scope){
var items = [];
//1.向服務器發起請求
//2.解析響應并放到Items對象
//3.將Items數組設置到$scope上,以便視圖能夠顯示
$scope.items = items;
}

- 這種做法雖然可行,但卻存在很多問題:
    * 功能代碼無法重用:同樣的代碼片段,如果其他控制器也需要從服務端獲取商品列表時,卻只能重寫一遍,這會給代碼維護工作造成很大的負擔;
    * 混淆控制器與與獲取數據功能之間的代碼邊界:獲取數據功能如果需要加上一些,例如服務器認證、解析數據等因素時,代碼的復雜性將變得不可控制;
    * 難以進行單元測試:進行測試的工作變得復雜,甚至可能需要真正啟動一個服務器來返回模擬數據進行測試,使得測試工作難以把控;
  通過模塊化和Angular內置的依賴注入功能,可以這樣寫:

//創建模塊
var myApp = angular.module('shoppingModule',[]);
//設置服務工廠
shoppingModule.factory('Items',function(){
var items = {};
items.query = function(){
//這里返回虛擬數據,真實的場景是從服務器拉取數據
return [
{name : 'Mary Contrary',id:1},
{name : 'Jack Spart',id:2},
{name : 'Jill Hill',id:3},
{name : 'William Liang',id:4},
{name : 'Yoki Chen',id:5}
];
};
return items;
});
//調用
function ShoppingController($scope,Items){
$scope.items = items.query();
}

  我們把`Items`對象定義成一個服務,把`$scope`對象和`Items`服務作為參數傳遞進去。
  > 提示:傳遞Angular在創建控制器時,是通過參數名匹配來注入所需要的服務的,比如`ShoppingController($scope,Items)`中查找`Items`服務。由于是以字符串的形式查找依賴關系的,所以控制器的參數是沒有順序的。

- 服務在Angular當中都是單例的對象,它們用來執行不要的任務,支撐應用的功能。開發者通過創建自定義的服務,共享在控制器之間,實現代碼的復用。
- Angular內置了很多服務,例如`location`服務,用來和瀏覽器的地址欄做交互;還有`router`服務,用來根據URL地址的變化切換視圖;以及`http`服務,用來和服務器進行交互等等;
- 根據Angular的API,有三種創建服務的函數:
  * __`provider(name,Object OR constructor())`__ :`name`是服務的名字,后面接一個對象或者構造函數。如果是Object的話,對象當中必須返回一個名為`$get()`的函數,否則Angular會認為傳遞的是一個構造函數,通過調用改構造函數返回服務的實例;
  * __`factory(name,$getFunction())`__ :和`provider()`函數相似,服務名后面接一個構造函數,當調用這個函數時,會返回服務的實例;
  * __`service(name,constructor())`__ :和`constructor`參數類似,Angular調用它來創建服務實例;
> 需要注意的是:Angular內置服務通常以符號開頭,為了避免命名沖突,定義服務名時應當避免以$符號打頭。

- 服務自身可以相互依賴,也可以通過`Module`接口定義模塊之間的依賴關系。比如:A模塊要引用SnazzyUIWidgets和SuperDataSync模塊

var appMod = angular.module('app',['SnazzyUIWidgets','SuperDataSync']);




### 使用過濾器格式數據
- 合理化地在應用界面中顯示數字、日期以及金額對于用戶體驗來說是很重要的,但這些字符串的格式化處理對邏輯來說是沒有意義的。
- Angular通過過濾器來格式化數據,其語法是:`{{expression | filterName : parameter1 : ...parameterN }}`
- `expression`可以是任意的Angular表達式,`filter`是需要使用的過濾器名稱,過濾器通過管道符號`|`來綁定,過濾器的參數之間使用冒號`:`分隔。
- 案例:Angular內置了眾多過濾器幫助我們格式化數據,同時也可以創建自定義的過濾器

//大小寫轉換
{{ "lower cap string" | uppercase }} //結果:LOWER CAP STRING
{{ "TANK is GOOD" | lowercase }} //結果:tank is good
//JSON格式化
{{ {foo: "bar", baz: 23} | json }} //結果:{ "foo": "bar", "baz": 23 }
//時間或日期格式化
{{ 1304375948024 | date:"yyyy-MM-dd hh:mm:ss" }} //結果:2011-05-03 06:39:08
//數字格式化
{{ 1.234567 | number:1 }} //結果:1.2
//金額格式化
{{ 250 | currency:"人民幣: ¥ " }} //結果:“人民幣: ¥ 250.00 ”
//排序格式化
{
{ [{"age": 20,"id": 10,"name": "iphone"},
{"age": 12,"id": 11,"name": "sunm xing"},
{"age": 44,"id": 12,"name": "test abc"}
] | orderBy:'id':true }} //根id降序排
//查找格式化
{
{ [{"age": 20,"id": 10,"name": "iphone"},
{"age": 12,"id": 11,"name": "sunm xing"},
{"age": 44,"id": 12,"name": "test abc"}
] | filter:'s'}} //查找含有有s的行
//字符串截取的格式化
{{ "i love tank" | limitTo:6 }} //結果:i love
{{ "i love tank" | limitTo:-4 }} //結果:tank



### 使用路由和$location切換視圖
- 雖然從技術角度來說,Ajax應用是單頁面應用,但很多時候處于各種原因,我們需要切換跳轉頁面,而Angular的`$router`服務負責應對這樣的場景。
- 路由服務機制是這樣定義的:當瀏覽器指向特定的URL時,Angular會加載顯示一個模板,并實例化一個控制器為此模板提供內容。
- 開發者可以通過`$routerProvider`服務的函數來創建路由,把需要創建的路由當做一個配置項傳遞給這些函數。

//創建模塊
var someModule = angular.module('someModule',[...module dependencies...]);
someModule.config(function($routerProvider){
//通過$routerProvider定義url對應的跳轉動作所需要的模板和控制器
$routerProvider.
when('url',{controller:aController,templateUrl:'/path/to/tempate'}).
othenwise('badUrl',{controller:notFoundController,templateUrl:'/path/to/tempate'});
});



### 與服務器交互
- Angular提供的`$http`服務使得與服務器交互更加容易。它支持HTTP、JSONP和CORS方式。它還包含了安全性支持,避免JSON格式的脆弱性和XSRF。

function ShoppingController($scope,$http){
$http.get('/products').success(function(data,status,headers.config){
$scope.items = data;
});
};



### 使用指令修改DOM
- Angular指令擴展了HTML的語法,通過自定義的元素或者屬性,把行為和DOM轉換關聯到一起。通過Angular可以創建可復用的UI組件。
- Angular指令創建語法:(directiveFn是一個工廠函數,用來定義指令的特性)

var app = angular.module('myapp',[]);
app.directive(name,fn);

- 案例:定義ts-hello指令,向DOM中輸出“Hello,Angular Directive!”

<!DOCTYPE html>
<html ng-app="DirectiveTestApp">
<head>
<meta charset="UTF-8">
<title>AngularJS Directive</title>
<style></style>
</head>
<script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
<body>
<div ng-controller="SomeController">
<ts-hello></ts-hello>
<div ts-hello></div>
<div class="ts-hello"></div>
<div data-ts-hello></div>
</div>
</body>
<script type="text/javascript">
var app = angular.module('DirectiveTestApp', []);
app.directive("tsHello",function(){
return {
restrict : 'EAC',
template : '<h5>Hello,Angular Directive!</h5>'
}
});
</script>
</html>



### 校驗用戶輸入
- 在表單校驗上,Angular允許開發者為表單的元素定義一個個發的狀態,只有當所有元素都是合法狀態時,才允許提交表單。
- 案例:一個用戶注冊頁面,要求必須輸入用戶名和郵箱,使用H5的required屬性

<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>Sign Up</h1>
<form name="addUserForm" ng-controller="AddUserController">
<div ng-show="message">{{message}}</div>
First name : <input name="firstName" required/>
Last name : <input name="lastName" required/>
Email : <input name="email" required type="email"/>
Age : <input name="age" required type="number"/>
<button ng-click="addUser()" ng-disabled="!addUserForm.$valid">Submit</button>
</form>
<script src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
<script type="text/javascript">
var myApp = angular.module('myApp',[]);
myApp.controller('AddUserController',function($scope){
$scope.message = '';
$scope.AddUser = function(){
alert("add user success!");
}
});
</script>
</body>
</html>

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,055評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,346評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,889評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,118評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,637評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,558評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,739評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,980評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,347評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,702評論 2 370

推薦閱讀更多精彩內容