基礎ng屬性指令
布爾屬性
布爾屬性代表一個true
或false
值。當這個屬性出現(xiàn)時,這個屬性的值就是true
(無論實際定義的值是什么)。如果未出現(xiàn),這個屬性的值就是false
。
當在AngularJS中使用動態(tài)數(shù)據(jù)綁定時,不能簡單地將這個屬性值設置為ture
或false
,因為 根據(jù)標準定義只有當這個屬性不出現(xiàn)時,它的值才為false
。因此AngularJS提供了一組帶有ng-
前綴版本的布爾屬性,通過運算表達式的值來決定在目標元素上是插入還是移除對應的屬性。
1.ng-disabled
使用ng-disabled
可以把disabled
屬性綁定到以下表單輸入字段上:
<input> (text、checkbox、radio、number、url、email、submit);<textarea>;<select>;<button>。
當寫普通的HTML輸入字段時,如果在元素標簽上出現(xiàn)了disabled
屬性就會禁用這個輸入字段。通過ng-disabled
可以對是否出現(xiàn)屬性進行綁定。
<input type="text" ng-model="someProperty" placeholder="TypetoEnable">
<button ng-model="button" ng-disabled="!someProperty">AButton</button>
在下面的例子,文本字段會被禁用五秒,直到在$timeout
中將isDisabled
屬性設置為true
。
<textarea ng-disabled="isDisabled">Wait5seconds</textarea>
angular.module('myApp', [])
.run(function($rootScope, $timeout) {
$rootScope.isDisabled = true;
$timeout(function() {
$rootScope.isDisabled = false;
}, 5000);
});
2.ng-readonly
通過ng-readonly
可以將某個返回真或假的表達式同是否出現(xiàn)readonly
屬性進行綁定。
Type here to make sibling readonly:
<input type="text" ng-model="someProperty"><br/>
<input type="text" ng-readonly="someProperty" value="Some text here"/>
3.ng-checked
通過ng-checked
將某個表達式同是否出現(xiàn)checked
屬性進行綁定。
//默認會把復選框勾選
<label>someProperty={{someProperty}}</label>
<input type="checkbox" ng-checked="someProperty" ng-init="someProperty=true" ng-model="someProperty">
4.ng-selected
ng-selected
可以對是否出現(xiàn)option
標簽的selected
屬性進行綁定。
<label>Select Two Fish:</label>
<input type="checkbox" ng-model="isTwoFish"><br/>
<select>
<option>One Fish</option>
<option ng-selected="isTwoFish">Two Fish</option>
</select>
類布爾屬性
ng-href
、ng-src
等屬性雖然不是標準的HTML布爾屬性,但是由于行為相似,所以在AngularJS源碼內(nèi)部是和布爾屬性同等對待的。
1.ng-href
當使用當前作用域中的屬性動態(tài)創(chuàng)建URL時,應該用ng-href
代替href
。
這里的潛在問題是當用戶點擊一個由插值動態(tài)生成的鏈接時,如果插值尚未生效,將會跳轉到錯誤的頁面(通常是404)。這時,如果使用ng-href
,AngularJS會等到插值生效后再執(zhí)行點擊鏈接的行為。
<!-- 當href包含一個{{expression}}時總是使用ng-href-->
<a ng-href="{{ myHref }}">I'm feeling lucky, when I load</a>
<!-- 用戶單擊之前,href不會加載 -->
<a href="{{myHref}}">I'm feeling 404</a>
將插值生效的事件延遲兩秒,來觀察實際的行為。
angular.module('myApp',[]).run(function($rootScope,$timeout) {
$timeout(function() {
$rootScope.my;
}, 2000);
});
2.ng-src
AngularJS會告訴瀏覽器在ng-src
對應的表達式生效之前不要加載圖像。
<h1>WrongWay</h1>
<img src="{{imgSrc}}"/>
<h1>Rightway</h1>
<img ng-src="{{imgSrc}}"/>
angular.module('myApp',[]).run(function($rootScope,$timeout) {
$timeout(function() {
$rootScope.imgSrc='https://www.google.com/images/srpr/logo11w.png';
}, 2000);
});
在指令中使用子作用域
ng-app
和ng-controller
是特殊的指令,因為它們會修改嵌套在它們內(nèi)部的指令的作用域。
ng-app
為AngularJS應用創(chuàng)建$rootScope
,ng-controller
則會以$rootScope
或另外一個ng-controller
的作用域為原型創(chuàng)建新的子作用域。
1.ng-app
任何具有ng-app
屬性的DOM元素將被標記為$rootScope
的起始點。$rootScope
是作用域鏈的起始點,任何嵌套在ng-app
內(nèi)的指令都會繼承它。在JS代碼中通過run
方法來訪問$rootScope
。
<html ng-app="myApp">
<body>
{{ someProperty }}
<button ng-click="someAction()"></button>
</body>
</html>
angular.module('myApp',[]).run(function($rootScope) {
$rootScope.someProperty='hello computer';
$rootScope.someAction=function() {
$rootScope.someProperty='hello human';
};
});
2.ng-controller
內(nèi)置指令ng-controller
的作用是為嵌套在其中的指令創(chuàng)建一個子作用域,避免將所有操作和模型都定義在$rootScope
上。用這個指令可以在一個DOM元素上放置控制器。
ng-controller
接受一個參數(shù)expression
,這個參數(shù)是必需的。expression
參數(shù)是一個AngularJS表達式。
子$scope
只是一個JS對象,其中含有從父級$scope
中通過原型繼承得到的方法和屬性,包括應用的$rootScope
。嵌套在ng-controller
中的指令有訪問新子$scope
的權限。
$scope
對象的職責是承載DOM中指令所共享的操作和模型。操作指的是$scope
上的標準JS方法。模型指的是$scope
上保存的包含瞬時狀態(tài)數(shù)據(jù)的JS對象。持久化狀態(tài)的數(shù)據(jù)應該保存到服務中,服務的作用是處理模型的持久化。
<div ng-controller="SomeController">
{{ someModel.someProperty }}
<button ng-click="someAction()">Communicate</button>
</div>
angular.module('myApp',[]).controller('SomeController',function($scope) {
//創(chuàng)建模型
$scope.someModel = {
// 添加屬性
someProperty: 'hello computer'
}
// 設置$scope自身的操作
$scope.someAction = function() {
$scope.someModel.someProperty = 'hello human';
};
});
在這個例子中,首先,我們使用了$rootScope
的子作用域,它提供了一個干凈的對象供我們操作。使用子作用域意味著其上的數(shù)據(jù)模型和操作在應用的其他地方是無法訪問的,只能被這個作用域內(nèi)的指令及其子作用域訪問。其次,顯式聲明了數(shù)據(jù)模型。
<div ng-controller="SomeController">
{{ someBareValue }}
<button ng-click="someAction()">Communicate to child</button>
<div ng-controller="ChildController">
{{ someBareValue }}
<button ng-click="childAction()">Communicate to parent</button>
</div>
</div>
angular.module('myApp',[]).controller('SomeController',function($scope) {
// 反模式,裸值
$scope.someBareValue = 'hello computer';
// 設置 $scope 本身的操作,這樣沒問題
$scope.someAction = function() {
//在SomeController和ChildController中設置{{someBareValue}}
$scope.someBareValue = 'hello human, from parent';
};
})
.controller('ChildController', function($scope) {
$scope.childAction = function() {
// 在ChildController中設置{{ someBareValue }}
$scope.someBareValue = 'hello human, from child';
};
});
這個例子中,在已有的控制器中嵌套了第二個控制器,并且沒有設置模型對象的屬性。由于原型繼承的關系,修改父級對象中的someBareValue
會同時修改子對象中的值,但反之則不行。這個例子充分說明了子控制器是復制而非引用someBareValue
。
如果將模型對象的某個屬性設置為字符串,它會通過引用進行共享,因此在子$scope
中修改屬性也會修改父$scope
中的這個屬性。下面的例子展示了正確的做法:
<div ng-controller="SomeController">
{{ someModel.someValue }}
<button ng-click="someAction()">Communicate to child</button>
<div ng-controller="ChildController">
{{ someModel.someValue }}
<button ng-click="childAction()">Communicate to parent</button>
</div>
</div>
angular.module('myApp', [])
.controller('SomeController', function($scope) {
// 最佳實踐,永遠使用一個模式
$scope.someModel = {
someValue: 'hello computer'
}
$scope.someAction = function() {
$scope.someModel.someValue = 'hello human, from parent';
};
})
.controller('ChildController', function($scope) {
$scope.childAction = function() {
$scope.someModel.someValue = 'hello human, from child';
};
});
無論點擊哪個按鈕,值都會進行同步修改。
注意,雖然這個特性是使用ng-controller
時最重要的特性之一,但在使用任何會創(chuàng)建子作用域的指令時,如果將指令定義中的scope
設置為true
,這個特性也會帶來負面影響。下面的內(nèi)置指令都有同樣的特性:ng-include
、ng-switch
、ng-repeat
、ng-view
、ng-controller
、ng-if
。
3.ng-include
使用ng-include
可以加載、編譯并包含外部HTML片段到當前的應用中。模板的URL被限制在與應用文檔相同的域和協(xié)議下,可以通過白名單或包裝成被信任的值來突破限制。更進一步,需要考慮跨域資源共享(CORS)和同源規(guī)則來確保模板可以在任何瀏覽器中正常加載。
使用ng-include
時AngularJS會自動創(chuàng)建一個子作用域。如果你想使用某個特定的作用域,例如ControllerA
的作用域,必須在同一個DOM元素上添加ng-controller="ControllerA"
指令,這樣當模板加載完成后,不會像往常一樣從外部作用域繼承并創(chuàng)建一個新的子作用域。
<div ng-include="other.html" ng-controller="MyController" ng-init="name='World'">
Hello {{name}}
</div>
<!--ng-include等價寫法-->
<div ng-include src="other.html">
Hello {{name}}
</div>
4.ng-switch
這個指令和ng-switch-when
及on="propertyName"
一起使用,可以在propertyName
發(fā)生變化時渲染不同指令到視圖中。
<input type="text" ng-model="person.name"/>
<div ng-switch on="person.name">
<p ng-switch-default>And the winner is</p>
<h1 ng-switch-when="Ari">{{person.name}}</h1>
</div>
在switch
被調用之前用ng-switch-default
來輸出默認值。
5.ng-view
ng-view
指令用來設置將被路由管理和放置在HTML中的視圖的位置。
6.ng-if
使用ng-if
指令可以完全根據(jù)表達式的值在DOM中生成或移除一個元素。如果賦值給ng-if
的表達式的值是false
,那對應的元素將會從DOM中移除,否則對應元素的一個克隆將被重新插入DOM中。
ng-if
同ng-show
和ng-hide
指令最本質的區(qū)別是,它不是通過CSS顯示或隱藏DOM節(jié)點,而是真正生成或移除節(jié)點。當一個元素被ng-if
從DOM中移除,同它關聯(lián)的作用域也會被銷毀。而且當它重新加入DOM中時,會通過原型繼承從它的父作用域生成一個新的作用域。
ngIf
重新創(chuàng)建元素時用的是它們編譯后的狀態(tài)。如果ng-if
內(nèi)部的代碼加載之后被jQuery修改過(例如用.addClass
),那么當ng-if
的表達式值為false
時,這個DOM元素會被移除,表達式再次成為true
時這個元素及其內(nèi)部的子元素會被重新插入DOM,此時這些元素的狀態(tài)會是它們的原始狀態(tài),而不是它們上次被移除時的狀態(tài)。也就是說無論用jQuery的.addClass
添加了什么類都不會存在了。
<div ng-if="2+2===4">
Hi, I do exist
</div>
7.ng-repeat
ng-repeat
用來遍歷一個集合或為集合中的每個元素生成一個模板實例。集合中的每個元素都會被賦予自己的模板和作用域。同時每個模板實例的作用域中都會暴露一些特殊的屬性。
- $index:遍歷的進度(0...
length-1
) - $first:當元素是遍歷的第一個時值為
true
- $middle:當元素處于第一個和最后元素之間時值為
true
- $last:當元素是遍歷的最后一個時值為
true
- $even:當
$index
值是偶數(shù)時值為true
- $odd:當
$index
值是奇數(shù)時值為true
<ul ng-controller="PeopleController">
<li ng-repeat="person in people" ng-class="{even:!$even, odd:!$odd}">
{{person.name}} lives in {{person.city}}
</li>
</ul>
.odd { background-color: blue;}
.even { background-color: red;}
angular.module('myApp',[]).controller('PeopleController',function($scope) {
$scope.people = [
{name: "Ari", city: "Beijing"},
{name: "Erik", city: "Seattle"}
];
});
8.ng-init
ng-init
指令用來在指令被調用時設置內(nèi)部作用域的初始狀態(tài)。
<div ng-init="greeting='Hello';person='World'">
{{greeting}} {{person}}
</div>
9. {{ }}
{{ }}
語法是AngularJS內(nèi)置的模板語法,它會在內(nèi)部$scope
和視圖之間創(chuàng)建綁定。基于這個綁定,只要$scope
發(fā)生變化,視圖就會隨之自動更新。
事實上它也是指令,是ng-bind
的簡略形式,用這種形式不需要創(chuàng)建新的元素,因此它常被用在行內(nèi)文本中。在屏幕可視的區(qū)域內(nèi)使用{{ }}
會導致頁面加載時未渲染的元素發(fā)生閃爍,用ng-bind
可以避免這個問題。
<body ng-init="greeting='HelloWorld'">
{{greeting}}
</body>
10.ng-bind
盡管可以在視圖中使用{{ }}
模板語法,我們也可以通過ng-bind
指令實現(xiàn)同樣的行為。
<body ng-init="greeting='HelloWorld'">
<p ng-bind="greeting"></p>
</body>
HTML加載含有{{ }}
語法的元素后并不會立刻渲染它們,導致未渲染內(nèi)容閃爍。我可以用ng-bind
將內(nèi)容同元素綁定在一起避免未渲染內(nèi)容閃爍。內(nèi)容會被當作子文本節(jié)點渲染到含有ng-bind
指令的元素內(nèi)。
11.ng-cloak
除使用ng-bind
來避免未渲染元素閃爍,還可以在含有{{ }}
的元素上使用ng-cloak
指令。
<body ng-init="greeting='HelloWorld'">
<p ng-cloak>{{ greeting }}</p>
</body>
ng-cloak
指令會將內(nèi)部元素隱藏,直到路由調用對應的頁面時才顯示出來。
12.ng-bind-template
同ng-bind
指令類似,ng-bind-template
用來在視圖中綁定多個表達式。
<div ng-bind-template="{{message}}{{name}}"></div>
13.ng-model
ng-model
指令用來將input、select、text area
或自定義表單控件同包含它們的作用域中的屬性進行綁定。它可以提供并處理表單驗證功能,在元素上設置相關的CSS類(ng-valid、ng-invalid
等),并負責在父表單中注冊控件。
它將當前作用域中運算表達式的值同給定的元素進行綁定。如果屬性并不存在,它會隱式創(chuàng)建并將其添加到當前作用域中。
我們應該始終用ngModel
來綁定$scope
上一個數(shù)據(jù)模型內(nèi)的屬性,而不是$scope
上的屬性,這可以避免在作用域或后代作用域中發(fā)生屬性覆蓋。
<input type="text" ng-model="modelName.someProperty" />
14.ng-show和ng-hide
ng-show
和ng-hide
根據(jù)所給表達式的值來顯示或隱藏HTML元素。當賦值給ng-show
指令的值為false
時元素會被隱藏。類似地,當賦值給ng-hide
指令的值為true
時元素也會被隱藏。
元素的顯示或隱藏是通過移除或添加ng-hide
這個CSS類來實現(xiàn)的。.ng-hide
類被預先定義在了AngularJS的CSS文件中,并且它的display
屬性的值為none
(用了!important
標記)。
<div ng-show="2 + 2 == 5">
2 + 2 isn't 5, don't show
</div>
<div ng-hide="2 + 2 == 4">
2 + 2 is 4, do hide
</div>
15.ng-change
這個指令會在表單輸入發(fā)生變化時計算給定表達式的值。因為要處理表單輸入,這個指令要和ngModel
聯(lián)合起來使用。
<div ng-controller="EquationController">
<input type="text" ng-model="equation.x" ng-change="change()" />
<code>{{ equation.output }}</code>
</div>
angular.module('myApp',[])
.controller('EquationController',function($scope) {
$scope.equation = {};
$scope.change = function() {
$scope.equation.output= parseInt($scope.equation.x) + 2;
};
});
上面的例子中,只要文本輸入字段中的內(nèi)容發(fā)生了變化就會改變equation.x
的值,進而運行change()
函數(shù)。
16.ng-form
ng-form
用來在一個表單內(nèi)部嵌套另一個表單。普通的HTML <form>
標簽不允許嵌套,但ng-form
可以。這意味著內(nèi)部所有的子表單都合法時,外部的表單才會合法。這對于用ng-repeat
動態(tài)創(chuàng)建表單是非常有用的。
由于不能通過字符插值來給輸入元素動態(tài)地生成name
屬性,所以需要將ng-form
指令內(nèi)每組重復的輸入字段都包含在一個外部表單元素內(nèi)。
下面的CSS類會根據(jù)表單的驗證狀態(tài)自動設置:
- 表單合法時設置
ng-valid
- 表單不合法時設置
ng-invlid
- 表單未進行修改時設置
ng-pristion
- 表單進行過修改時設置
ng-dirty
AngularJS不會將表單提交到服務器,除非它指定了action
屬性。要指定提交表單時調用哪個JS方法,使用下面兩個指令中的一個。
- ng-submit:在表單元素上使用。
- ng-click:在第一個按鈕或
submit
類型的輸入字段上使用。
為了避免處理程序被多次調用,只使用兩個指令中的一個。
下面的例子展示了如何通過服務器返回的JSON數(shù)據(jù)動態(tài)生成一個表單。我們用ng-loop
來遍歷從服務器取回的所有數(shù)據(jù)。由于不能動態(tài)生成name
屬性,而我們又需要這個屬性做驗證,所以在循環(huán)的過程中會為每一個字段都生成一個新表單。
由于AngularJS中用來取代<form>
的ng-form
指令可以嵌套,并且外部表單在所有子表單都合法之前一直處于不合法狀態(tài),因此我們可以在動態(tài)生成子表單的同時使用表單驗證功能。
angular.module('myApp',[])
.controller('FormController',function($scope) {
$scope.fields = [
{placeholder: 'Username', isRequired: true},
{placeholder: 'Password', isRequired: true},
{placeholder: 'Email (optional)', isRequired: false}
];
$scope.submitForm = function() {
alert("it works!");
};
});
下面用這些數(shù)據(jù)生成一個有驗證功能的動態(tài)表單:
<form name="signup_form" ng-controller="FormController" ng-submit="submitForm()" novalidate>
<div ng-repeat="field in fields" ng-form="signup_form_input">
<input type="text" name="dynamic_input" ng-required="field.isRequired" ng-model="field.name" placeholder="{{field.placeholder}}" />
<div ng-show="signup_form_input.dynamic_input.$dirty && signup_form_input.dynamic_input.$invalid">
<span class="error" ng-show="signup_form_input.dynamic_input.$error.required">
The field is required.
</span>
</div>
</div>
<button type="submit" ng-disabled="signup_form.$invalid">Submit All</button>
</form>
input.ng-invalid {border: 1px solid red;}
input.ng-valid {border: 1px solid green;}
17.ng-click
ng-click
用來指定一個元素被點擊時調用的方法或表達式。
<div ng-controller="CounterController">
<button ng-click="count=count+1" ng-init="count=0">Increment</button>
count: {{ count }}
<button ng-click="decrement()">Decrement</button>
<div>
angular.module('myApp',[]).controller('CounterController',function($scope) {
$scope.decrement = function() {
$scope.count = $scope.count-1;
};
})
18.ng-select
ng-select
用來將數(shù)據(jù)同HTML的<select>
元素進行綁定。這個指令可以和ng-model
以及ng-options
指令一同使用。
ng-options
可以接受一個數(shù)組或對象,并對它們進行循環(huán),將內(nèi)部的內(nèi)容提供給select
標簽內(nèi)部的選項。它可以是下面兩種形式。
數(shù)組作為數(shù)據(jù)源:
- 用數(shù)組中的值做標簽;
- 用數(shù)組中的值作為選中的標簽;
- 用數(shù)組中的值做標簽組;
- 用數(shù)組中的值作為選中的標簽組。
對象作為數(shù)據(jù)源:
- 用對象的鍵值(
key-value
)做標簽; - 用對象的鍵值作為選中的標簽;
- 用對象的鍵值作為標簽組;
- 用對象的鍵值作為選中的標簽組。
<div ng-controller="CityController">
<select ng-model="city" ng-options="city.name for city in cities">
<option value="">Choose City</option>
</select>
Best City: {{ city.name }}
</div>
angular.module('myApp',[]).controller('CityController',function($scope) {
$scope.cities = [
{name: 'Seattle'},
{name: 'San Francisco'},
{name: 'Chicago'},
{name: 'New York'}
];
});
19.ng-submit
ng-submit
用來將表達式同onsubmit
事件進行綁定。這個指令同時會阻止默認行為(發(fā)送請求并重新加載頁面),除非表單不含有action
屬性。
<form ng-submit="submit()" ng-controller="FormController">
Enter text and hit enter:
<input type="text" ng-model="person.name" name="person.name" />
<input type="submit" name="person.name" value="Submit" />
<code>people={{people}}</code>
<ul ng-repeat="(index, object) in people">
<li>{{ object.name }}</li>
</ul>
</form>
angular.module('myApp',[]).controller('FormController',function($scope) {
$scope.person={ name:null};
$scope.people=[];
$scope.submit=function() {
if ($scope.person.name) {
$scope.people.push({name: $scope.person.name});
$scope.person.name = '';
}
};
});
20.ng-class
使用ng-class
動態(tài)設置元素的類,方法是綁定一個代表所有需要添加的類的表達式。重復的類不會添加。當表達式發(fā)生變化,先前添加的類會被移除,新類會被添加。
<div ng-controller="LotteryController">
<div ng-class="{red:x>5}" ng-if="x>5">You won!</div>
<button ng-click="x=generateNumber()" ng-init="x=0">Draw Number</button>
<p>Number is: {{ x }}</p>
</div>
.red {background-color: red;}
angular.module('myApp',[]).controller('LotteryController',function($scope) {
$scope.generateNumber = function() {
return Math.floor((Math.random()*10)+1);
};
});
21.ng-attr-(suffix)
當AngularJS編譯DOM時會查找花括號{{some expression}}
內(nèi)的表達式。這些表達式會被自動注冊到$watch
服務中并更新到$digest
循環(huán)中,成為它的一部分。
<-- updated when`someExpression` on the$scope is updated -->
<h1>Hello{{someExpression}}</h1>
有時瀏覽器會對屬性進行很苛刻的限制。SVG就是一個例子:
<svg>
<circle cx="{{cx}}"></circle>
</svg>
運行上面的代碼會拋出一個錯誤,指出我們有一個非法屬性。可以用ng-attr-cx
來解決這個問題。注意,cx
位于這個名稱的尾部。在這個屬性中,通過用{{ }}
來寫表達式,達到前面提到的目的。
<svg>
<circle ng-attr-cx="{{cx}}"><circle>
</svg>