學習筆記之AngularJS(二)

一、控制器和作用域

控制器是通過AngularJS的Module對象所提供的controller方法而創建出來的。controller方法的參數是新建控制器的名字和一個將被用於創建控制器的函數。

當控制器聲明瞭對於Scope服務的依賴時,就可以使得控制器通過其對應的作用域向視圖提供各種能力。 但嚴格地說,$scope並不是一個服務,而是由一個叫作$rootScope的服務所提供的一個對象,在實際應用中,$scope的使用與服務極爲相像,所以簡單起見將其稱爲一個服務。

爲什麼使用控制器及作用域:

控制器是模型與視圖之間的紐帶。它從模型中暴露數據給視圖,以及基於用戶與試圖的交互使模型產生變化所需的邏輯。

什麼時候使用:

控制器的使用遍及整個AngularJS程序,它可用於向所支持的視圖提供作用域。

(一)組織控制器

1. 單塊控制器

(1)示例

<!DOCTYPE html>
<html ng-app="exampleApp">
<head>
    <title>Controllers</title>
    <script src="../angular.js"></script>
    <link href="../bootstrap.css" rel="stylesheet" />
    <link href="../bootstrap-theme.css" rel="stylesheet" />
    <script>
        angular.module("exampleApp", [])
            .controller("simpleCtrl", function ($scope) {
            // 當控制器聲明瞭對於Scope服務的依賴時,就可以使得控制器通過其對應的作用域向視圖提供各種能力。
                $scope.addresses = {};

                $scope.setAddress = function (type, zip) {
                    console.log("Type: " + type + " " + zip);
                    $scope.addresses[type] = zip;
                }

                $scope.copyAddress = function () {
                    $scope.shippingZip = $scope.billingZip;
                }
            });
    </script>
</head>
<body ng-controller="simpleCtrl">

<div class="well">
    <h4>Billing Zip Code</h4>
    <div class="form-group">
        <input class="form-control" ng-model="billingZip">
    </div>
    <button class="btn btn-primary" ng-click="setAddress('billingZip', billingZip)">
        Save Billing
    </button>
</div>

<div class="well">
    <h4>Shipping Zip Code</h4>
    <div class="form-group">
        <input class="form-control" ng-model="shippingZip">
    </div>
    <button class="btn btn-primary" ng-click="copyAddress()">
        Use Billing
    </button>
    <button class="btn btn-primary"
            ng-click="setAddress('shippingZip', shippingZip)">
        Save Shipping
    </button>
</div>
</body>
</html>

(2)運行結果

 

2. 複用控制器

(1)作用域之間的通信

① 用於發送和接收事件的作用域方法

Method

Description

$broadcast(name, args)

Sends an event from the current scope down to all of the child scopes. The arguments are the name of the event and an object used to provide supplementary data with the event.

$emit(name, args)

Sends an event from the current scope up to the root scope.

$on(name, handler)

Registers a handler function that is invoked when the specified event is received by the scope.

 

② 示例:使用根作用域通信

<!DOCTYPE html>
<html ng-app="exampleApp">
<head>
    <title>Controllers</title>
    <script src="../../angular.js"></script>
    <link href="../../bootstrap.css" rel="stylesheet" />
    <link href="../../bootstrap-theme.css" rel="stylesheet" />
    <script>
        angular.module("exampleApp", [])
            .controller("simpleCtrl", function ($scope, $rootScope) {

                $scope.$on("zipCodeUpdated", function (event, args) {
                    $scope[args.type] = args.zipCode;
                });

                $scope.setAddress = function (type, zip) {
/*                  當“Save Billing”按鈕被單擊時,$broadcast方法在根作用域中被調用,
                    向下發送一個zipCodeUpdate事件給作用域的各個層級。*/
                    $rootScope.$broadcast("zipCodeUpdated", {
                        type: type, zipCode: zip
                    });
                    console.log("Type: " + type + " " + zip);
                }
/*                setAddress函數的觸發,使作用域與真正知道和採集Billing ZIP Code的控制器得到了聯繫。
                    使得“Use Billing”按鈕得以恢復使用*/
                $scope.copyAddress = function () {
                    $scope.zip = $scope.billingZip;
                }
            });
    </script>

</head>
<body>
<div class="well" ng-controller="simpleCtrl">
    <h4>Billing Zip Code</h4>
    <div class="form-group">
        <input class="form-control" ng-model="zip">
    </div>
    <button class="btn btn-primary" ng-click="setAddress('billingZip', zip)">
        Save Billing
    </button>
</div>
<div class="well" ng-controller="simpleCtrl">
    <h4>Shipping Zip Code</h4>
    <div class="form-group">
        <input class="form-control" ng-model="zip">
    </div>
    <button class="btn btn-primary" ng-click="copyAddress()">
        Use Billing
    </button>
    <button class="btn btn-primary" ng-click="setAddress('shippingZip', zip)">
        Save Shipping
    </button>
</div>
</body>
</html>

 

(2)使用服務調解作用域事件

① 示例

<!DOCTYPE html>
<html ng-app="exampleApp">
<head>
    <title>Controllers</title>
    <script src="../../angular.js"></script>
    <link href="../../bootstrap.css" rel="stylesheet" />
    <link href="../../bootstrap-theme.css" rel="stylesheet" />
    <script>
        angular.module("exampleApp", [])
/*            ZipCodes服務中聲明瞭對$rootScope服務的依賴,並在setZipCoode方法中使用它來調用$broadcast事件。
        這種慣用法將可能被不同的控制器所需使用的代碼放在同一地方,達到了減少重複的目的*/
            .service("ZipCodes", function($rootScope) {
                return {
                    setZipCode: function(type, zip) {
                        this[type] = zip;
                        $rootScope.$broadcast("zipCodeUpdated", {
                            type: type, zipCode: zip
                        });
                    }
                }
            })
            .controller("simpleCtrl", function ($scope, ZipCodes) {

                $scope.$on("zipCodeUpdated", function (event, args) {
                    $scope[args.type] = args.zipCode;
                });

                $scope.setAddress = function (type, zip) {
                    ZipCodes.setZipCode(type, zip);
                    console.log("Type: " + type + " " + zip);
                }

                $scope.copyAddress = function () {
                    $scope.zip = $scope.billingZip;
                }
            });
    </script>
</head>
<body>
<div class="well" ng-controller="simpleCtrl">
    <h4>Billing Zip Code</h4>
    <div class="form-group">
        <input class="form-control" ng-model="zip">
    </div>
    <button class="btn btn-primary" ng-click="setAddress('billingZip', zip)">
        Save Billing
    </button>
</div>
<div class="well" ng-controller="simpleCtrl">
    <h4>Shipping Zip Code</h4>
    <div class="form-group">
        <input class="form-control" ng-model="zip">
    </div>
    <button class="btn btn-primary" ng-click="copyAddress()">
        Use Billing
    </button>
    <button class="btn btn-primary" ng-click="setAddress('shippingZip', zip)">
        Save Shipping
    </button>
</div>
</body>
</html>

 

3. 使用控制器繼承

當查找行爲時,AngularJS 會從 該指令所應用到的控制器的作用域上開始查找。如果該行爲存在,就將會被執行。 如果不存在,AngularJS將會向作用域層級的上一層繼續查找,直到具有指定名稱的行爲被找到。可以利用這一特性在大多數時候使用父控制器中所提供的功能,而只改寫需要自定義的部分。這允許你創建爲應用程序的不同部分量身定做的控制器,而無需從父控制器中拷貝代碼和數據。

(1)示例

<!DOCTYPE html>
<html ng-app="exampleApp">
<head>
    <title>Controllers</title>
    <script src="../../angular.js"></script>
    <script src="controllers.js"></script>
    <link href="../../bootstrap.css" rel="stylesheet" />
    <link href="../../bootstrap-theme.css" rel="stylesheet" />
</head>
<!--父級控制器-->
<body ng-controller="topLevelCtrl">

<div class="well">
    <h4>Top Level Controller</h4>
    <div class="input-group">
            <span class="input-group-btn">
                <button class="btn btn-default" type="button"
                        ng-click="reverseText()">Reverse</button>
                <button class="btn btn-default" type="button"
                        ng-click="changeCase()">Case</button>
            </span>
        <input class="form-control" ng-model="dataValue">
    </div>
</div>
<!--子控制器,嵌入在父級控制器內-->
<div class="well" ng-controller="firstChildCtrl">
    <h4>First Child Controller</h4>
    <div class="input-group">
            <span class="input-group-btn">
                <!--“Reverse”按鈕調用頂層控制器中定義的reverseText行爲,-->
                <button class="btn btn-default" type="button"
                        ng-click="reverseText()">Reverse</button>
                <!--“Case”按鈕調用firstChildCtrl控制器的changeCase-->
                <button class="btn btn-default" type="button"
                        ng-click="changeCase()">Case</button>
            </span>
        <input class="form-control" ng-model="dataValue">
    </div>
</div>

<div class="well" ng-controller="secondChildCtrl">
    <h4>Second Child Controller</h4>
    <div class="input-group">
            <span class="input-group-btn">
                <button class="btn btn-default" type="button"
                        ng-click="reverseText()">Reverse</button>
                <button class="btn btn-default" type="button"
                        ng-click="changeCase()">Case</button>
                <button class="btn btn-default" type="button"
                        ng-click="shiftFour()">Shift</button>
            </span>
        <input class="form-control" ng-model="dataValue">
    </div>
</div>
</body>
</html>

(2)運行結果

 

因爲reverseText行爲和數據是在父控制器上定義的,然後被子控制器繼承,所以點擊任意一個“Reverse”,都能起作用

 

點擊First Child Controller的“Case”後,點擊任意一個“Reverse”,First Child Controller的值都沒有變化。

原因如下:

當讀取一個直接在作用域上定義的屬性的值時,AngularJS會檢查在這個控制器的作用域上是否有一個局部屬性, 如果沒有,就會沿着作用域層次結構向上查找是否有一個被繼承的屬性。然而,當使用ng-model指令來修改這樣一個屬性時,AngularJS會檢查當前作用域是否有這樣一個名稱的屬性,如果沒有,就會假設你想隱式定義一個這樣的屬性。結果便是覆蓋了該屬性值,就像在前面一節中的行爲那樣。而至於編輯了子控制器中的輸入框之後, 就會影響“Reverse”按鈕的工作的原因是因爲現在會有兩個 dataValue 屬性一個是被頂層控制器所定義的, 另一個是被編輯的子控制器所定義的。 reverseText行爲是在頂層控制器中定義的,只對頂層作用域中定義的dataValue屬性起作用,而不會改變子作用域中的data.Value屬性。

③ 解決方案:

Inheritance solution.html

<!DOCTYPE html>
<html ng-app="exampleApp">
<head>
    <title>Controllers</title>
    <script src="../../angular.js"></script>
    <script src="Inheritance Solution.js"></script>
    <link href="../../bootstrap.css" rel="stylesheet" />
    <link href="../../bootstrap-theme.css" rel="stylesheet" />
</head>
<body ng-controller="topLevelCtrl">

<div class="well">
    <h4>Top Level Controller</h4>
    <div class="input-group">
            <span class="input-group-btn">
                <button class="btn btn-primary" type="button"
                        ng-click="reverseText()">Reverse</button>
                <button class="btn btn-primary" type="button"
                        ng-click="changeCase()">Case</button>
            </span>
        <input class="form-control" ng-model="data.dataValue">
    </div>
</div>

<div class="well" ng-controller="firstChildCtrl">
    <h4>First Child Controller</h4>
    <div class="input-group">
            <span class="input-group-btn">
                <button class="btn btn-primary" type="button"
                        ng-click="reverseText()">Reverse</button>
                <button class="btn btn-primary" type="button"
                        ng-click="changeCase()">Case</button>
            </span>
        <input class="form-control" ng-model="data.dataValue">
    </div>
</div>

<div class="well" ng-controller="secondChildCtrl">
    <h4>Second Child Controller</h4>
    <div class="input-group">
            <span class="input-group-btn">
                <button class="btn btn-primary" type="button"
                        ng-click="reverseText()">Reverse</button>
                <button class="btn btn-primary" type="button"
                        ng-click="changeCase()">Case</button>
                <button class="btn btn-primary" type="button"
                        ng-click="shiftFour()">Shift</button>
            </span>
        <input class="form-control" ng-model="data.dataValue">
    </div>
</div>
</body>
</html>

Inheritance solution.js

var app = angular.module("exampleApp", []);

app.controller("topLevelCtrl", function ($scope) {

    $scope.data = {
        dataValue: "Hello, Adam"
    }

    $scope.reverseText = function () {
        $scope.data.dataValue = $scope.data.dataValue.split("").reverse().join("");
    }

    $scope.changeCase = function () {
        var result = [];
        angular.forEach($scope.data.dataValue.split(""), function (char, index) {
            result.push(index % 2 == 1
                ? char.toString().toUpperCase() : char.toString().toLowerCase());
        });
        $scope.data.dataValue = result.join("");
    };
});

app.controller("firstChildCtrl", function ($scope) {

    $scope.changeCase = function () {
        $scope.data.dataValue = $scope.data.dataValue.toUpperCase();
    };
});

app.controller("secondChildCtrl", function ($scope) {

    $scope.changeCase = function () {
        $scope.data.dataValue = $scope.data.dataValue.toLowerCase();
    };

    $scope.shiftFour = function () {
        var result = [];
        angular.forEach($scope.data.dataValue.split(""), function (char, index) {
            result.push(index < 4 ? char.toUpperCase() : char);
        });
        $scope.data.dataValue = result.join("");
    }
});

此時,將文件中的其他對dataValue屬性的引用修改爲對data對象的該屬性進行訪問。所以,任意一個按鈕對每個值都起作用。

 

4. 使用多控制器

<!DOCTYPE html>
<html ng-app="exampleApp">
<head>
    <title>Controllers</title>
    <script src="../../angular.js"></script>
    <link href="../../bootstrap.css" rel="stylesheet" />
    <link href="../../bootstrap-theme.css" rel="stylesheet" />
    <script>
        var app = angular.module("exampleApp", []);

        app.controller("firstController", function ($scope) {

            $scope.dataValue = "Hello, Adam";

            $scope.reverseText = function () {
                $scope.dataValue = $scope.dataValue.split("").reverse().join("");
            }
        });

        app.controller("secondController", function ($scope) {

            $scope.dataValue = "Hello, Jacqui";

            $scope.changeCase = function () {
                $scope.dataValue = $scope.dataValue.toUpperCase();
            };
        });
    </script>
</head>
<body>
<div class="well" ng-controller="firstController">
    <h4>First Controller</h4>
    <div class="input-group">
            <span class="input-group-btn">
                <button class="btn btn-primary" type="button"
                        ng-click="reverseText()">Reverse</button>
            </span>
        <input class="form-control" ng-model="dataValue">
    </div>
</div>

<div class="well" ng-controller="secondController">
    <h4>Second Controller</h4>
    <div class="input-group">
            <span class="input-group-btn">
                <button class="btn btn-primary" type="button"
                        ng-click="changeCase()">
                    Case
                </button>
            </span>
        <input class="form-control" ng-model="dataValue">
    </div>
</div>
</body>
</html>

 

(二)使用無作用域的控制器

<!DOCTYPE html>
<html ng-app="exampleApp">
<head>
    <title>Controllers</title>
    <script src="../angular.js"></script>
    <link href="../bootstrap.css" rel="stylesheet" />
    <link href="../bootstrap-theme.css" rel="stylesheet" />
    <script>
        var app = angular.module("exampleApp", [])
            .controller("simpleCtrl", function () {
                this.dataValue = "Hello, Adam";

                this.reverseText = function () {
                    this.dataValue = this.dataValue.split("").reverse().join("");
                }
            });
    </script>
</head>
<body>
<div class="well" ng-controller="simpleCtrl as ctrl">
    <h4>Top Level Controller</h4>
    <div class="input-group">
            <span class="input-group-btn">
                <button class="btn btn-primary" type="button"
                        ng-click="ctrl.reverseText()">Reverse</button>
            </span>
        <input class="form-control" ng-model="ctrl.dataValue">
    </div>
</div>
</body>
</html>

(三) 顯式地更新作用域

1. 作用域集成方法

Method

Description

$apply(expression)

Applies a change to the scope

$watch(expression, handler)

Registers a handler that will be notified when the value referred to by the expression changes

$watchCollection(object, handler)

Registers a handler that will be notified when any of the properties of the specified object change

2. 示例

<!DOCTYPE html>
<html ng-app="exampleApp">
<head>
    <title>Controllers</title>
    <script src="../angular.js"></script>
    <link href="../bootstrap.css" rel="stylesheet" />
    <link href="../bootstrap-theme.css" rel="stylesheet" />
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js">
    </script>
    <link rel="stylesheet" href=
            "http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/sunny/jquery-ui.min.css">
    <script>
        $(document).ready(function () {
            $('#jqui button').button().click(function (e) {
                angular.element(angularRegion).scope().$apply('handleClick()');
            });
        });

        var app = angular.module("exampleApp", [])
            .controller("simpleCtrl", function ($scope) {
                $scope.buttonEnabled = true;
                $scope.clickCounter = 0;

                $scope.handleClick = function () {
                    $scope.clickCounter++;
                }

                $scope.$watch('buttonEnabled', function (newValue) {
                    $('#jqui button').button({
                        disabled: !newValue
                    });
                });
            });
    </script>

</head>
<body>
<div id="angularRegion" class="well" ng-controller="simpleCtrl">
    <h4>AngularJS</h4>
    <div class="checkbox">
        <label>
            <input type="checkbox" ng-model="buttonEnabled"> Enable Button
        </label>
    </div>
    Click counter: {{clickCounter}}
</div>
<div id="jqui" class="well">
    <h4>jQuery UI</h4>
    <button>Click Me!</button>
</div>
</body>
</html>

 

3. 運行結果


 

二、 使用過濾器

(一)過濾單個數據的值

Name

Description

currency

This filter formats currency values.

date

This filter formats date values.

json

This filter generates an object from a JSON string.

number

This filter formats a numeric value.

uppercase

These filters format a string into all uppercase or lowercase letters.

lowercase

(二)date過濾器支持的格式化字符串成分

Component

 Description

yyyy

 A four-digit representation of the year (e.g., 2050)

yy

A two-digit representation of the year (e.g., 50)

MMMM

The full month name (e.g., January)

MMM

Short representation of the month (e.g., Jan)

MM

Numeric month, padded to two characters (e.g., 01)

M

Numeric month, without padding (e.g., 1)

dd

Day of month, padded to two characters (e.g., 02)

d

Day of month, no padding (e.g., 2)

EEEE

Full name of day of week (e.g., Tuesday)

EEE

Short name of day of week (e.g., Tue)

HH

Hour in day, 24-hour clock with padding to two characters (e.g., 02)

H

Hour in day, 24-hour clock without padding (e.g., 2)

hh

Hour in day, 12-hour clock with padding to two characters (e.g., 02)

h

Hour in day, 12-hour clock without padding (e.g., 2)

mm

Minute in hour, padded to two characters (e.g., 02)

m

Minute in hour without padding (e.g., 2)

ss

Second in minute, padded to two characters (e.g., 02)

s

Second in minute without padding (e.g., 2)

a

Marker for a.m./p.m.

Z

Four-character representation of time zone

(三)date過濾器支持的快捷格式字符串

Formatting

String Description

medium

Equivalent to MMM d, y h:mm:ss a

short

Equivalent to M/d/yy h:mm a

fullDate

Equivalent to EEEE, MMMM d,y

longDate

Equivalent to MMMM d, y

mediumDate

Equivalent to MMM d, y

shortDate

Equivalent to M/d/yy

mediumTime

Equivalent to h:mm:ss a

shortTime

Equivalent to h:mm a

medium

Equivalent to MMM d, y h:mm:ss a

(四)示例

Filter.js

angular.module("exampleApp")
    .filter("labelCase", function () {
        return function (value, reverse) {
            if (angular.isString(value)) {
                var intermediate =  reverse ? value.toUpperCase() : value.toLowerCase();
                return (reverse ? intermediate[0].toLowerCase() :
                    intermediate[0].toUpperCase()) + intermediate.substr(1);
            } else {
                return value;
            }
        };
    })
    .filter("skip", function () {
        return function (data, count) {
            if (angular.isArray(data) && angular.isNumber(count)) {
                if (count > data.length || count < 1) {
                    return data;
                } else {
                    return data.slice(count);
                }
            } else {
                return data;
            }
        }
    })
    // take過濾器依賴於skip和limitTo過濾器,讓他們執行自己的校驗並應用自己的轉化過程,就像被直接使用一樣。
    .filter("take", function ($filter) {
    return function (data, skipCount, takeCount) {
        // 過濾器在worker函數中通過名稱來訪問和調用
        var skippedData = $filter("skip")(data, skipCount);
        return $filter("limitTo")(skippedData, takeCount);
    }

});

Filter.html

<html ng-app="exampleApp">
<head>
    <title>Filters</title>
    <meta charset="utf-8">
    <script src="../angular.js"></script>
    <link href="../bootstrap.css" rel="stylesheet"/>
    <link href="../bootstrap-theme.css" rel="stylesheet"/>
    <script>
        angular.module("exampleApp", [])
            .controller("defaultCtrl", function ($scope) {
                $scope.products = [
                    {name: "Apples", category: "Fruit", price: 1.20, expiry: 10},
                    {name: "Bananas", category: "Fruit", price: 2.42, expiry: 7},
                    {name: "Pears", category: "Fruit", price: 2.02, expiry: 6},

                    {name: "Tuna", category: "Fish", price: 20.45, expiry: 3},
                    {name: "Salmon", category: "Fish", price: 17.93, expiry: 2},
                    {name: "Trout", category: "Fish", price: 12.93, expiry: 4},

                    {name: "Beer", category: "Drinks", price: 2.99, expiry: 365},
                    {name: "Wine", category: "Drinks", price: 8.99, expiry: 365},
                    {name: "Whiskey", category: "Drinks", price: 45.99, expiry: 365}
                ];

                $scope.getExpiryDate = function (days) {
                    var now = new Date();
                    return now.setDate(now.getDate() + days);
                }

                $scope.limitVal = "5";
                $scope.limitRange = [];
                for (var i = (0 - $scope.products.length);
                     i <= $scope.products.length; i++) {
                    $scope.limitRange.push(i.toString());
                }
                $scope.selectItems = function (item) {
                    return item.category == "Fish" || item.name == "Beer";
                };
                $scope.myCustomSorter = function (item) {
                    return item.expiry < 5 ? 0 : item.price;
                };

            });
    </script>
    <script src="Filter.js"></script>
    <script src="angular-locale_fr-fr.js"></script>
</head>
<body ng-controller="defaultCtrl">
<div class="panel panel-default">
    <div class="panel-heading">
        <h3>
            Products
            <span class="label label-primary">{{products.length}}</span>
        </h3>
    </div>
    <div class="panel-body">
        Limit: <select ng-model="limitVal"
                       ng-options="item for item in limitRange"></select>
    </div>
    <div class="panel-body">
        <table class="table table-striped table-bordered table-condensed">
            <thead>
            <tr>
                <td>Name</td>
                <td>Category</td>
                <td>Expiry:date</td>
                <td>Expiry:shortDate</td>
                <td>Price:currency</td>
                <td>Price:number</td>
            </tr>
            </thead>
            <tbody>
            <!--對products數組應用了limitTo過濾器:limitTo:limitVal-->
            <!--選取項:filter:selectItems或filter:{category:'Fish'}形式-->
            <!--對項目排序:orderBy:'-price',隱式爲升序,加“-”爲降序-->
            <!--使用函數排序:orderBy:myCustomSorter-->
            <!--使用多個謂語進行排序:orderBy:[myCustomSorter,'-price']-->
            <!--使用自定義集合過濾器:skip:2-->
            <!--在已有的過濾器上搭建take過濾器:take:2:5,值用冒號分隔-->
            <tr ng-repeat="p in products | limitTo:limitVal | orderBy:myCustomSorter| take:2:5">
                <!--改變字符串大小寫:uppercase過濾器和lowercase過濾器-->
                <td>{{p.name | uppercase}}</td>
                <!--使用自定義過濾器-->
                <td>{{p.category |  labelCase}}</td>
                <!--格式化日期:date過濾器-->
                <td>{{getExpiryDate(p.expiry)| date:"dd MMM yy"}}</td>
                <!--本地化過濾器輸出:-->
                <td>{{getExpiryDate(p.expiry) | date:"shortDate"}}</td>
                <!--格式化貨幣值:currency過濾器-->
                <td class="text-right">{{p.price | currency:"¥"}}</td>
                <!--格式化其他數字值:number-->
                <td class="text-right">{{p.price | number: 0}}</td>
            </tr>
            <tr ng-repeat="p in products">
                <td colspan="4">{{p|json}}</td>
            </tr>
            </tbody>
        </table>
    </div>
</div>
</body>
</html>

 

三、 創建自定義指令

(一)實現鏈接函數並打破數據屬性的依賴

1. 示例:

<html ng-app="exampleApp">
<head>
    <title>Directives</title>
    <script src="../angular.js"></script>
    <link href="../bootstrap.css" rel="stylesheet" />
    <link href="../bootstrap-theme.css" rel="stylesheet" />
    <script>
        angular.module("exampleApp", [])
            .directive("unorderedList", function () {
                // 因爲scope, element, attrs參數只是普通的Javascripte參數,而不是通過依賴注入提供的。所以傳入鏈接函數的對象的順序是固定的
                return function (scope, element, attrs) {
                    // 從作用域獲取數據,使用unorderedList來獲取unordered-list屬性的值
                    var data = scope[attrs["unorderedList"]];
                    // 添加對指令屬性的支持
                    var propertyName=attrs["listProperty"]
                    if (angular.isArray(data)) {
                        // 調用angular.element方法創建一個新元素並且在element參數上使用append方法向文檔中插入這個新元素
                        var listElem = angular.element("<ul>");
                        element.append(listElem);
                        for (var i = 0; i < data.length; i++) {
                            // 如果沒有jqLite對象卻需要一個(例如要創建一個新元素時),就可以使用angular.element方法
                            // 兩種方法都返回jqLite對象,可以用於調用其他的jqLite方法,稱爲方法鏈技術
                            listElem.append(angular.element('<li>')
                                .text(data[i][propertyName]));
                        }
                    }
                }
            })
            .controller("defaultCtrl", function ($scope) {
                $scope.products = [
                    { name: "Apples", category: "Fruit", price: 1.20, expiry: 10 },
                    { name: "Bananas", category: "Fruit", price: 2.42, expiry: 7 },
                    { name: "Pears", category: "Fruit", price: 2.02, expiry: 6 }
                ];
            });
    </script>
</head>
<body ng-controller="defaultCtrl">
<div class="panel panel-default">
    <div class="panel-heading">
        <h3>Products</h3>
    </div>
    <div class="panel-body">
        <!--應用自定義指令-->
        <!--這裏將該指令用作div元素上的一個屬性,但是請注意屬性名和傳給directive方法的參數有所不同:是unordered-list而不是unorderList.-->
        <div unordered-list="products" list-property="name"></div>
    </div>
</div>
</body>
</html>

2. 運行結果:

 

(二)處理數據變化

1. 示例:

<html ng-app="exampleApp">
<head>
    <title>Directives</title>
    <script src="../angular.js"></script>
    <link href="../bootstrap.css" rel="stylesheet" />
    <link href="../bootstrap-theme.css" rel="stylesheet" />
    <script>
        angular.module("exampleApp", [])
            .directive("unorderedList", function () {
                return function (scope, element, attrs) {
                    var data = scope[attrs["unorderedList"]];
                    var propertyExpression = attrs["listProperty"];

                    if (angular.isArray(data)) {
                        var listElem = angular.element("<ul>");
                        element.append(listElem);
                        for (var i = 0; i < data.length; i++) {
                            // 定義“立即調用函數的表達式”(IIFE),這個函數會被立即計算。結構:(function(){.....}());
                            (function () {
                                var itemElement = angular.element('<li>');
                                listElem.append(itemElement);
                                // 對閉包特性加以控制, 以便使用一個固定的或有界的變量來引用數據對象
                                var index=i;
                                var watcherFn = function (watchScope) {
                                    // 監聽函數
                                    // IIFE是在一定義時就被執行的,所以index的值將不會被for循環的下一個迭代所更新
                                    return watchScope.$eval(propertyExpression, data[index]);
                                }
                                    // 添加watch方法來監控作用域中的變化,將監聽器函數傳給$watch方法並指定回調函數
                                    scope.$watch(watcherFn, function (newValue, oldValue) {
                                        // 回調函數使用jqLite 的 text 函數更新 li 元素的文本內容,以反映數據值的變化
                                        itemElement.text(newValue);
                                    });
                            }());
                        }
                    }
                }
            })

            .controller("defaultCtrl", function ($scope) {
                $scope.products = [
                    { name: "Apples", category: "Fruit", price: 1.20, expiry: 10 },
                    { name: "Bananas", category: "Fruit", price: 2.42, expiry: 7 },
                    { name: "Pears", category: "Fruit", price: 2.02, expiry: 6 }
                ];

                $scope.incrementPrices = function () {
                    for (var i = 0; i < $scope.products.length; i++) {
                        $scope.products[i].price++;
                    }
                }
            })
    </script>
</head>
<body ng-controller="defaultCtrl">
<div class="panel panel-default">
    <div class="panel-heading">
        <h3>Products</h3>
    </div>
    <div class="panel-body">
        <button class="btn btn-primary" ng-click="incrementPrices()">
            Change Prices
        </button>
    </div>
    <div class="panel-body">
        <div unordered-list="products" list-property="price | currency"></div>
    </div>
</div>
</body>
</html>

2. 運行結果:

 

(三)使用jqLite工作

1. 對文檔對象模型導航及修改元素

(1)關於DOM導航的jqLite方法

Name

Description

children()

Returns the set of child elements. The jqLite implementation of this method does not support the selectors feature that jQuery provides.

eq(index)

Returns an element at the specified index from a collection of elements.

find(tag)

Locates all of the descendant elements with the specified tag name. The jQuery implementation provides additional options for selecting elements, which are not available in the jqLite implementation of this method.

next()

Gets the next sibling element. The jqLite implementation of this method does not support the selectors feature that jQuery provides.

parent()

Returns the parent element. The jqLite implementation of this method does not support the selectors feature that jQuery provides.

(2)用於修改元素的jqLite方法

Name

Description

addClass(name)

Adds all of the elements in the jqLite object to the specified class.

attr(name)

attr(name, value)

Gets the value of the specified attribute for the first element in the jqLite object or sets the specified value for all of the elements.

css(name)

css(name, value)

Gets the value of the specified CSS property from the first element or sets the property to the specified value for all the elements in the jqLite object.

hasClass(name)

Returns true if any of the elements in the jqLite object belong to the specified class.

prop(name)

prop(name, value)

Gets the value of the specified property for the first element in the jqLite object or sets the specified value for all of the elements.

removeAttr(name)

Removes the attribute from all of the elements in the jqLite object.

removeClass(name)

Removes the elements in the jqLite object from the specified class.

text()

text(value)

Gets the concatenated text content from all the elements or sets the text content for all the elements in the jqLite object.

toggleClass(name)

Toggles membership of the specified class for all the elements in the jqLite object. Those elements that were not in the class will be added to it, and those that were in the class will be removed from it.

val()

val(value)

Gets the value attribute for the first element or sets the value attribute for all the elements in the jqLite object.

(3)示例

<html ng-app="exampleApp">
<head>
    <title>Directives</title>
    <script src="../../angular.js"></script>
    <script>
        angular.module("exampleApp", [])
            .directive("demoDirective", function () {
                return function (scope, element, attrs) {
                    // var items = element.children();
                    var items = element.find("li");
                    // 使用css方法設置CSS顏色屬性
                    items.css("color","red");
                    // 使用eq方法訪問元素
                    for (var i = 0; i < items.length; i++) {
                        if (items.eq(i).text() == "Oranges") {
                            items.eq(i).css("font-weight", "bold");
                        }
                    }
                }
            })
            .controller("defaultCtrl", function ($scope) {
                // controller defines no data or behaviors
            })
    </script>
</head>
<body ng-controller="defaultCtrl">
    <h3>Fruit</h3>
    <!--demoDirective指令處理所應用到元素的子元素-->
    <ol demo-directive>
        <li>Apples</li>
        <ul>
            <li>Bananas</li>
            <li>Cherries</li>
            <li>Oranges</li>
        </ul>
        <li>Oranges</li>
        <li>Pears</li>
    </ol>
</body>
</html>

(4)運行結果

 

2. 創建和移除元素

(1)用於創建和移除元素的jqLite

Name

Description

angular.element(html)

Creates a jqLite object that represents the element specified by the HTML string

after(elements)

Inserts the specified content after the element on which the method is called

append(elements)

Inserts the specified elements as the last child of each element in the jqLite object on which the method has been called

clone()

Returns a new jqLite object that duplicates the elements from the object on which the method is called

prepend(elements)

Inserts the specified elements as the first child of each element in the jqLite object on which the method has been called

remove()

Removes the elements in the jqLite object from the DOM

replaceWith(elements)

 

Replaces the elements in the jqLite object on which the method is called with the specified elements

wrap(elements)

Wraps each element in the jqLite object with the specified elements

 

3. 用於處理事件的jqLite方法

Name

Description

on(events, handler)

Registers a handler for one or more events emitted by the elements represented by the jqLite object. The jqLite implementation of this method does not support the selectors or event data features that jQuery provides.

off(events, handler)

Removes a previously registered handler for the specified events from the elements represented by the jqLite object. The jqLite implementation of this method does not support the selectors feature that jQuery provides.

triggerHandler(event)

Triggers all of the handlers for the specified event registered on the elements

4. 其他jqLite方法

Name

Description

data(key, value)

data(key)

Associates arbitrary data with all the elements or retrieves a value for the specified key from the first element represented by the jqLite object

removeData(key)

Removes data associated with the specified key from the elements represented by the jqLite object

html()

Returns an HTML representation of the content of the first element represented by the jqLite object

ready(handler)

Registers a handler function that will be invoked once the contents of the DOM are fully loaded

5. 從jqLite訪問AngularJS的特性

(1)可以訪問AngularJS特性的其他方法

Name

Description

controller()

controller(name)

Returns the controller associated with the current element or its parent.

injector()

Returns the injector associated with the current element or its parent.

isolatedScope()

Returns an isolated scope if there is one associated with the current element.

scope()

Returns the scope associated with the current element or its parent.

inheritedData(key)

This method performs the same function as the jQuery data method but will walk up the element hierarchy looking for a value to match the specified key.

6. 示例

<html ng-app="exampleApp">
<head>
    <title>Directives</title>
    <script src="../../angular.js"></script>
    <script>
        angular.module("exampleApp", [])
            .directive("demoDirective", function () {
                return function (scope, element, attrs) {
/*
                    原代碼:
                    var listElem = element.append("<ol>");
                    for (var i = 0; i < scope.names.length; i++) {
                        listElem.append("<li>").append("<span>").text(scope.names[i]);
                    }
                    問題:每次for循環將字符串替換掉
*/
                    // 解決方案:使用angular.element方法創建jqLite對象並在單獨的語句中對他們執行各種操作
                    var listElem = angular.element("<ol>");
                    element.append(listElem);
                    for (var i = 0; i < scope.names.length; i++) {
                        listElem.append(angular.element("<li>")
                            .append(angular.element("<span>").text(scope.names[i])));
                    }
                    // 添加數據處理器
                    var buttons = element.find("button");
                    buttons.on("click",function (e) {
                        element.find("li").toggleClass("bold");
                    });
                }
            })

            .controller("defaultCtrl", function ($scope) {
                $scope.names = ["Apples", "Bananas", "Oranges"];
            })
    </script>
    <style>
        .bold { font-weight: bold; }
    </style>
</head>
<body ng-controller="defaultCtrl">
    <h3>Fruit</h3>
    <div demo-directive>
        <button>Click Me</button>
    </div>
</body>
</html>

 

7. 運行結果

 

(四)使用jQuery替換jqLite

1. 示例

<html ng-app="exampleApp">
<head>
    <title>Directives</title>
    <!--注意:jQuery腳本元素出現在加載AngularJS的腳本元素之前。如果直到AngularJS的後面才加載jQuery,那麼jqLite就會被使用。-->
    <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    <script src="../../angular.js"></script>
    <link href="../../bootstrap.css" rel="stylesheet" />
    <link href="../../bootstrap-theme.css" rel="stylesheet" />
    <script>
        angular.module("exampleApp", [])
            .directive("unorderedList", function () {
                return function (scope, element, attrs) {
                    var data = scope[attrs["unorderedList"]];
                    var propertyExpression = attrs["listProperty"];
                    if (angular.isArray(data)) {
/*
                        多行jqLite語句
                        var listElem = angular.element("<ul>");
                        element.append(listElem);

                        替換成jQuery語句:
*/
                        var listElem = angular.element("<ul>").appendTo(element);
                        for (var i = 0; i < data.length; i++) {
                            (function () {
                                var itemElement =
                                    angular.element("<li>").appendTo(listElem);
                                var index = i;
                                var watcherFn = function (watchScope) {
                                    return watchScope.$eval(propertyExpression,
                                        data[index]);
                                }
                                scope.$watch(watcherFn, function (newValue, oldValue) {
                                    itemElement.text(newValue);
                                });
                            }());
                        }
                    }
                }
            }).controller("defaultCtrl", function ($scope) {
            $scope.products = [
                { name: "Apples", category: "Fruit", price: 1.20, expiry: 10 },
                { name: "Bananas", category: "Fruit", price: 2.42, expiry: 7 },
                { name: "Pears", category: "Fruit", price: 2.02, expiry: 6 }
            ];

            $scope.incrementPrices = function () {
                for (var i = 0; i < $scope.products.length; i++) {
                    $scope.products[i].price++;
                }
            }
        })
    </script>
</head>

<body ng-controller="defaultCtrl">
<div class="panel panel-default">
    <div class="panel-heading">
        <h3>Products</h3>
    </div>
    <div class="panel-body">
        <button class="btn btn-primary" ng-click="incrementPrices()">
            Change Prices
        </button>
    </div>
    <div class="panel-body">
        <div unordered-list="products" list-property="price | currency"></div>
    </div>
</div>
</body>
</html>

四、 創建複雜指令

(一)定義複雜指令

1. 由指令定義對象所定義的屬性

Name

Description

compile

Specifies a compile function.

controller

Creates a controller function for the directive.

link

Specifies the link function for the directive.

replace

Specifies whether the contents of the template replace the element that the directive has been applied to.

require

Declares a dependency on a controller.

restrict

Specifies how the directive can be applied.

scope

Creates a new scope or an isolated scope for the directive.

template

Specifies a template that will be inserted into the HTML document.

templateUrl

Specifies an external template that will be inserted into the HTML document.

transclude

Specifies whether the directive will be used to wrap arbitrary content.

2. 用於配置restrict定義選項的字母

Letter

Description

E

Allows the directive to be applied as an element

A

Allows the directive to be applied as an attribute

C

Allows the directive to be applied as a class

M

Allows the directive to be applied as a comment

實際項目中很少有一個指令能夠以四種方式全部適用的,restrict定義屬性的最常見值是A(指令僅能被用作一個屬性)、E(指令僅能被用作一個元素),或者AE(指令可被用作一個元素或者一個屬性)。正如下面各節中將要解釋的,C和M選項鮮有用到。

 

3. 將指令當作一個元素使用

<div class="panel-body">
    <unordered-list list-source="products" list-property="price | currency" />
</div>

如果沒有可用的unordered-list屬性時,檢查新屬性的值:

var data = scope[attrs["unorderedList"] || attrs["listSource"]];

 

4. 將指令當作一個屬性使用

<div class="panel-body">
  <div unordered-list="products" list-property="price | currency"></div>
</div>

5. 將指令當作一個類的屬性值使用

<div class="panel-body">
    <div class="unordered-list: products, price | currency"></div>
</div>

6. 將指令當作一個註釋來使用

這個註釋必須以單詞directive開始,跟隨一個冒號、指令名以及可選的配置參數。

<div class="panel-body">
  <!-- directive: unordered-list products -->
</div>

用了可選參數來指定數據源井更新鏈接函數來設置屬性表達式的默認值:

var propertyExpression = attrs["listProperty"] || "price | currency";

使用jqLite定位並操作註釋元素的父元素,修改鏈接函數的操作方式以支持註釋方式:

if (element[0].nodeName == "#comment") {
  element.parent().append(listElem);
} else {
  element.append(listElem);

(二)使用指令模板

<html ng-app="exampleApp">
<head>
    <title>Directives</title>
    <script src="../../angular.js"></script>
    <link href="../../bootstrap.css" rel="stylesheet" />
    <link href="../../bootstrap-theme.css" rel="stylesheet" />
    <script>
        angular.module("exampleApp", [])
            .directive("unorderedList", function () {
                return {
                    link: function (scope, element, attrs) {
                        scope.data = scope[attrs["unorderedList"]];
                    },
                    restrict: "A",
                    template: "<ul><li ng-repeat='item in data'>"
                    + "{{item.price | currency}}</li></ul>"
                }
            }).controller("defaultCtrl", function ($scope) {
            $scope.products = [
                { name: "Apples", category: "Fruit", price: 1.20, expiry: 10 },
                { name: "Bananas", category: "Fruit", price: 2.42, expiry: 7 },
                { name: "Pears", category: "Fruit", price: 2.02, expiry: 6 }
            ];
        })
    </script>
</head>
<body ng-controller="defaultCtrl">
<div class="panel panel-default">
    <div class="panel-heading">
        <h3>Products</h3>
    </div>
    <div class="panel-body">
        <div unordered-list="products">
            This is where the list will go
        </div>
    </div>
</div>
</body>
</html>

1. 使用函數作爲模板

......
template: function () {
return angular.element(
document.querySelector("#listTemplate")).html();
}
......

2. 使用外部模板

......
templateUrl: "itemTemplate.html"
......
 <div unordered-list="products">
    This is where the list will go
</div>
......

3. 通過函數選擇一個外部模板

......
	templateUrl: function (elem, attrs) {
		return attrs["template"] == "table" ?
		"tableTemplate.html" : "itemTemplate.html";
}
......
    <div class="panel-body">
        <div unordered-list="products">
            This is where the list will go
        </div>
    </div>
    <div class="panel-body">
        <div unordered-list="products" template="table">
            This is where the list will go
        </div>
    </div>
......

4. 替換元素

replace屬性不僅僅知識用模板替換了元素,還將元素中的屬性也轉移給了模板內容

(1)示例

<html ng-app="exampleApp">
<head>
    <title>Directives</title>
    <script src="../../angular.js"></script>
    <link href="../../bootstrap.css" rel="stylesheet" />
    <link href="../../bootstrap-theme.css" rel="stylesheet" />
    <script>
        angular.module("exampleApp", [])
            .directive("unorderedList", function () {
                return {
                    link: function (scope, element, attrs) {
                        scope.data = scope[attrs["unorderedList"]];
                    },
                    restrict: "A",
                    templateUrl: "tableTemplate.html",
                    replace: true
                }

            }).controller("defaultCtrl", function ($scope) {
            $scope.products = [
                { name: "Apples", category: "Fruit", price: 1.20, expiry: 10 },
                { name: "Bananas", category: "Fruit", price: 2.42, expiry: 7 },
                { name: "Pears", category: "Fruit", price: 2.02, expiry: 6 }
            ];
        })
    </script>
</head>
<body ng-controller="defaultCtrl">
<div class="panel panel-default">
    <div class="panel-heading">
        <h3>Products</h3>
    </div>
    <div class="panel-body">
        <div unordered-list="products" class="table table-striped"
             ng-repeat="count in [1, 2, 3]">
            This is where the list will go
        </div>
    </div>
</div>
</body>
</html>

(2)運行結果:

無有 replace: true

 

(三)管理指令的作用域

默認情況下,鏈接函數被傳入了控制器的作用域,而該控制器管理着的視圖包含了指令所應用到的元素。

1.創建多個控制器並給每個指令實例創建其作用域

當無法控制所使用的指令的源代碼時,可以重用指令來爲指令的每個實例創建單獨的控制器,使得每個實例有自己的作用域。

(1)代碼示例:

<!DOCTYPE html>
<html ng-app="exampleApp">
<head>
    <title>Directive Scopes</title>
    <script src="../../angular.js"></script>
    <link href="../../bootstrap.css" rel="stylesheet" />
    <link href="../../bootstrap-theme.css" rel="stylesheet" />
    <script type="text/ng-template" id="scopeTemplate">
        <div class="panel-body">
            <p>Name: <input ng-model="data.name" /></p>
            <!--data.name這個屬性是在一個對象上定義的,意味着這個值將會在指令的各個實例之間所共享,而且所有綁定到該屬性的輸入框元素將會保持同步-->
            <p>City: <input ng-model="city" /></p>
            <!--city這個屬性是在控制器的作用域上被直接賦值的,意味着指令所有的作用域將會從同一個初始值開始,但是在輸入框元素被修改時會在自己的作用域上創建和修改自己的版本-->
            <p>Country: <input ng-model="country" /></p>
            <!--country這個屬性沒有被賦任何值。 當相應的輸入框元素被修改時, 指令的每個實例將會創建出獨立的country屬性-->
        </div>
    </script>
    <script type="text/javascript">
        angular.module("exampleApp", [])
            .directive("scopeDemo", function () {
                return {
                    template: function() {
                        return angular.element(
                            document.querySelector("#scopeTemplate")).html();
                    },
                    // 給每個指令創建自己的作用域:設置scope屬性爲true將允許在同一個控制器裏複用一個指令。
                    scope: true
                }
            })
            .controller("scopeCtrl", function ($scope) {
                $scope.data = { name: "Adam" };
                $scope.city = "London";
            })
            .controller("secondCtrl", function ($scope) {
                // do nothing - no behaviours required
            });
    </script>
</head>
<body>
<!--爲每個指令創建單獨控制器,使用兩個控制器,於是有了兩個作用域,這兩個作用域都有自己的name屬性,這允許輸入框元素可以各自獨立地運作。-->
<div ng-controller="scopeCtrl" class="panel panel-default">
    <!--一個指令的兩個實例,在用一個控制器上更新同一個name屬性-->
    <div class="panel-body" scope-demo></div>
    <div class="panel-body" scope-demo></div>
</div>
<div ng-controller="secondCtrl" class="panel panel-default">
    <div class="panel-body" scope-demo></div>
    <div class="panel-body" scope-demo></div>
</div>

</body>
</html>

(2)運行結果:

(3)作用域說明:

① 一個指令的不同實例在控制器作用域上操作:

② 爲指令的每個實例創建一個控制器的效果:

③ 在單個控制器裏給每個指令實例自己的作用域:

 

2.創建隔離的作用域

在創建一個打算在許多各種不同情況下複用的指令時,以及不想要任何由控制器或作用域層次上的其他地方定義的對象和屬性導致的繼承時,可以創建一個隔離的作用域。

(1)通過屬性值進行單項綁定

①代碼示例:

<!DOCTYPE html>
<html ng-app="exampleApp">
<head>
    <title>Directive Scopes</title>
    <script src="../../../angular.js"></script>
    <link href="../../../bootstrap.css" rel="stylesheet" />
    <link href="../../../bootstrap-theme.css" rel="stylesheet" />
    <script type="text/ng-template" id="scopeTemplate">
        <div class="panel-body">
            <p>Data Value: {{local}}</p>
            <!--使用內聯的綁定表達式來顯示屬性local的值。-->
        </div>
    </script>
    <script type="text/javascript">
        angular.module("exampleApp", [])
            .directive("scopeDemo", function () {
                return {
                    template: function() {
                        return angular.element(
                            document.querySelector("#scopeTemplate")).html();
                    },
                    // 在 scope 定義對象中,設置了在指令作用域內一個特性和一個屬性之間的一個單項映射
                    // 指定了屬性 local 的值應該從一個來自名爲 nameprop 的特性的單向綁定來獲得。
                    scope: {
                        local: "@nameprop"
                    }
                }
            })
            .controller("scopeCtrl", function ($scope) {
                $scope.data = { name: "Adam" };
            });
    </script>
</head>
<body ng-controller="scopeCtrl">
<div class="panel panel-default">
    <div class="panel-body">
        Direct Binding: <input ng-model="data.name" />
    </div>
    <!--在元素上定義nameprop特性-->
    <div class="panel-body" scope-demo nameprop="{{data.name}}"></div>
    <!--通過單項數據綁定寵用一個指令-->
    <div class="panel-body" scope-demo nameprop="{{data.name + 'Freeman'}}"></div>
</div>
</body>
</html>

② 運行結果:

③ 在隔離作用域上的單項數據綁定的效果:

3.創建雙向綁定

(1)代碼示例

<!DOCTYPE html>
<html ng-app="exampleApp">
<head>
    <title>Directive Scopes</title>
    <script src="../../../angular.js"></script>
    <link href="../../../bootstrap.css" rel="stylesheet" />
    <link href="../../../bootstrap-theme.css" rel="stylesheet" />
    <script type="text/ng-template" id="scopeTemplate">
        <div class="panel-body">
            <!-- -->
            <!--傳遞來自隔離作用域的數據,更新計算表達式的模板中的綁定,傳入一個爲表達式參數提供值的對象-->
            <p>Name: {{local}}, City: {{cityFn({nameVal:local})}}</p>
        </div>
    </script>
    <script type="text/javascript">
        angular.module("exampleApp", [])
            .directive("scopeDemo", function () {
                return {
                    template: function () {
                        return angular.element(
                            document.querySelector("#scopeTemplate")).html();
                    },
                    scope: {
                        // “@”替換爲“=”
                        local: "=nameprop",
                        // 前綴“&”用於將city特性的值綁定到cityFn函數。
                        cityFn: "&city"
                    }
                }
            })
            .controller("scopeCtrl", function ($scope) {
                $scope.data = {
                    name: "Adam",
                    defaultCity: "London"
                };

                $scope.getCity = function (name) {
                    return name == "Adam" ? $scope.data.defaultCity : "Unknown";
                }
            });
    </script>
</head>
<body ng-controller="scopeCtrl">
<div class="panel panel-default">
    <div class="panel-body">
        Direct Binding: <input ng-model="data.name" />
    </div>
    <!--nameprop="{{data.name}}"去掉"{{}}"-->
    <!--修改表達式city="getCity(data.name)"以便傳遞給行爲的參數是在控制器作用域上沒有被定義過的屬性名-->
    <div class="panel-body" scope-demo
         city="getCity(data.name)" nameprop="data.name"></div>
</div>
</body>
</html>

(2)運行結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章