AngularJS框架可以用Service
和Directive
降低開發(fā)復(fù)雜性。這個(gè)特性非常適合用于分離代碼,創(chuàng)建可測(cè)試組件,然后將它們變成可重用組件。
Directive
是一組獨(dú)立的JavaScript、HTML和CSS,它們封裝了一個(gè)特定的行為,它將成為將來(lái)創(chuàng)建的Web組件的組成部分,我們可以在各種應(yīng)用中重用這些組件。在創(chuàng)建之后,我們可以直接通過一個(gè)HTML標(biāo)簽、自定義屬性或CSS類、甚至可以是HTML注釋,來(lái)執(zhí)行一個(gè)Directive。
這一篇教程將介紹如何創(chuàng)建一個(gè)自定義步長(zhǎng)選擇Directive,它可以作為一個(gè)可重用輸入組件。本文不僅會(huì)介紹Directive的一般創(chuàng)建過程,還會(huì)介紹輸入控件驗(yàn)證方法,以及如何使用ngModelController無(wú)縫整合任意表單,從而利用AngularJS表單的現(xiàn)有強(qiáng)大功能。
下面直接放出相關(guān)的代碼,
<body ng-app="demo" ng-controller="DemoController">
<form name="form" >
Model value : <input type="text" size="3" ng-model="rating"><br>
Min value: <input type="text" size="3" ng-model="minRating"><br>
Max value: <input type="text" size="3" ng-model="maxRating"><br>
Form has been modified : {{ form.$dirty }}<br>
Form is valid : {{ form.$valid }}
<hr>
<div min="minRating" max="maxRating" ng-model="rating" rn-stepper></div>
</form>
</body>
angular.module('demo', [
'revolunet.stepper'
]) .controller('DemoController', function($scope) {
$scope.rating = 42;
$scope.minRating = 40;
$scope.maxRating = 50;
});
rn-stepper
最簡(jiǎn)結(jié)構(gòu)// we declare a module name for our projet, and its dependencies (none)
angular.module('revolunet.stepper', [])
// declare our na?ve directive
.directive('rnStepper', function() {
return {
// can be used as attribute or element
restrict: 'AE',
// which markup this directive generates
template:
'<button>-</button>' +
'<div>0</div>' +
'<button>+</button>'
};
});
現(xiàn)在directive rnStepper 已經(jīng)有了一個(gè)簡(jiǎn)單的雛形了??梢杂腥缦聝煞N使用方法:
<div rn-stepper> </div>
<rn-stepper> </rn-stepper>
這里有一個(gè)demo
直接上代碼,
xxx.directive('rnStepper', function() {
return {
restrict: 'AE',
// declare the directive scope as private (and empty)
scope: {},
// add behaviour to our buttons and use a variable value
template:
'<button ng-click="decrement()">-</button>' +
'<div>{{value}}</div>' +
'<button ng-click="increment()">+</button>',
// this function is called on each rn-stepper instance initialisation
// we just declare what we need in the above template
link: function(scope, iElement, iAttrs) {
scope.value = 0;
scope.increment = function() {
scope.value++;
};
scope.decrement = function() {
scope.value--;
};
}
};
});
我們?cè)趖emplate中,分別給兩個(gè)button添加了click事件響應(yīng),在link方法中實(shí)現(xiàn)了響應(yīng)的方法。 這里的scope是一個(gè)private scope,其作用域僅限r(nóng)nStepper這個(gè)directive。
這里有一個(gè)demo
直到上面為止,我們的rnStepper
都是自己跟自己玩,并沒有跟外部作用域進(jìn)行一些交互。下面我們將添加一個(gè)數(shù)據(jù)綁定,使rnStepper與外部世界建立聯(lián)系。
我們給scope
添加一個(gè)value
屬性,
scope: {
value: '=ngModel'
}
我們?cè)趕cope中添加了一組鍵值對(duì),這樣,會(huì)自動(dòng)建立內(nèi)部變量value與外部屬性ngModel的聯(lián)系。 這里的=
代表的意思是雙向綁定(double data-binding)。
什么叫雙向綁定? 即: 當(dāng)value
發(fā)生改變,那么ngModel
也會(huì)發(fā)生改變,反之亦然。
在我們的這個(gè)demo中,看下面這行代碼:
<div rn-stepper ng-model="rating"></div>
這里的意思就是: directive rnStepper
的內(nèi)部變量value
與外部scope
中的rating
建立了雙向數(shù)據(jù)綁定。
這里有一個(gè)demo。
直接上代碼,
.directive('rnStepper', function() {
return {
// restrict and template attributes are the same as before.
// we don't need anymore to bind the value to the external ngModel
// as we require its controller and thus can access it directly
scope: {},
// the 'require' property says we need a ngModel attribute in the declaration.
// this require makes a 4th argument available in the link function below
require: 'ngModel',
// the ngModelController attribute is an instance of an ngModelController
// for our current ngModel.
// if we had required multiple directives in the require attribute, this 4th
// argument would give us an array of controllers.
link: function(scope, iElement, iAttrs, ngModelController) {
// we can now use our ngModelController builtin methods
// that do the heavy-lifting for us
// when model change, update our view (just update the div content)
ngModelController.$render = function() {
iElement.find('div').text(ngModelController.$viewValue);
};
// update the model then the view
function updateModel(offset) {
// call $parsers pipeline then update $modelValue
ngModelController.$setViewValue(ngModelController.$viewValue + offset);
// update the local view
ngModelController.$render();
}
// update the value when user clicks the buttons
scope.decrement = function() {
updateModel(-1);
};
scope.increment = function() {
updateModel(+1);
};
}
};
});
這里,我不在需要內(nèi)部變量value了。因?yàn)槲覀冊(cè)趌ink方法中已經(jīng)拿到了ngModelController
的引用,這里的ngModelController.$viewValue
其實(shí)就是前面例子中的value。
同時(shí)我們又添加了另外一組鍵值對(duì)require: ‘ngModel’。
我們使用了兩個(gè)新的API:
ngModelController.$render
: 在ngModel發(fā)生改變的時(shí)候框架自動(dòng)調(diào)用,同步$modelValue
和$viewValue
, 即刷新頁(yè)面。ngModelController.$setViewValue
: 當(dāng)$viewValue
發(fā)生改變時(shí),通過此方法,同步更新$modelValue
。這里有一個(gè)demo
更多建議: