基于jQuery UI Autocomplete的AngularJS 指令(directive)擴展
在前幾篇隨筆簡單介紹了AngularJS,在AngularJS 指令(directive)是重要的概念,主要負責了很大部分的組建樣式交互。在前面介紹過directive需要預先的模板編譯在返回一個link的函數,注冊行為事件交互等等。在這里不多說了,關于指令的介紹將在后續一并補上。在這里我們先看一個利用jQuery UI組件開發的AngularJS Autocomplete指令。
代碼:jsfiddle在線測試
Directive:
1 var oldSuggest = jQuery.ui.autocomplete.prototype._suggest;
2 jQuery.ui.autocomplete.prototype._suggest = function(items) {
3 var itemsArray = items;
4 if (this.options.maxItems && this.options.maxItems > 0) {
5 itemsArray = items.slice(0, this.options.maxItems);
6 }
7 oldSuggest.call(this, itemsArray);
8 };
9
10 var autocomplete = function() {
11 var linkFun = function($scope, element, attrs) {
12 var $input = jQuery(element);
13 var responseDataSource = function($scope, source, pattern, response) {
14 var express = $scope[source];
15 var data = typeof(express) === "function" ? express(pattern, response) : express;
16 if (data) {
17 response(data);
18 }
19 };
20 var option = attrs;
21 //
22 option.position = {
23 my: attrs.positionMy,
24 at: attrs.positionAt,
25 };
26 var option = jQuery.extend({
27 position: {
28 my: "",
29 at: ""
30 },
31 close: function(event, ui) {
32 var express = attrs["ngModel"] + "='" + $input.val() + "'";
33 $scope.$apply(express);
34 $scope.$eval(attrs["ngChange"]);
35 }
36 }, option);
37 option.remote = option.remote === "true";
38 if (!option.remote) {
39 option.dataSource = attrs.source;
40 option.source = function(pattern, response) {
41 var option = $input.autocomplete("option");
42 var responseEx = function(data) {
43 var matches = jQuery.map(data, function(tag) {
44 var startWith = attrs.startWith === "true";
45 var index = tag.toUpperCase().indexOf(pattern.term.toUpperCase())
46 if ((startWith && index === 0) || (!startWith && index > -1)) {
47 return tag;
48 }
49 })
50 response(matches);
51 };
52 responseDataSource($scope, option.dataSource, pattern, responseEx);
53 };
54 } else {
55 option.source = option.source; //remote url
56 }
57 $input.autocomplete(option);
58 };
59 return linkFun;
60 };
61
62 var prefixed = "green";
63 var appMoule = angular.module('app', []);
64
65 appMoule.directive(prefixed + "Autocomplete", autocomplete);
在指令中主需要標注html attribute green-autocomplete=””引用.
以及一些特殊option:
- Remote:(Boolean)是否為遠程調用,true則source為url,false則為scope上的一個屬性或者函數。
- Source:數據源,url、scope屬性或者函數。
- min-length:開始顯示下拉條的最小長度。
- position-my,position-at:jQuery下拉條顯示樣式
- start-with:(Boolean)是否為以前綴開始的帥選,默認false(包含)。
- max-items:顯示最大下拉項數目。
測試代碼:
html: 1 <div ng-app="app" ng-controller="Test">
2 <div class="ui-widget">
3 <label for="tags">Tags(變量): </label>
4 <input id="tags" ng-model="val" green-autocomplete="" remote="false" ng-disabled="val=='Asp'" source="getsource" min-length="0" position-my="right top" position-at= "right bottom" start-with="false">
5 </div>
6 <br/>
7 `val`
8
9 <div class="ui-widget">
10 <label for="tags">Tags(函數): </label>
11 <input i ng-model="val_Array" green-autocomplete="" source="availableTags" max-items="5" min-length="2" start-with="true" ng-change="change();">
12 </div>
13 <br/>`val_Array`
14 http://XX/XX.php?term={0}
15 <div class="ui-widget">
16 <label for="tags">Tags(url): </label>
17 <input i ng-model="val_url" green-autocomplete="" source="url" remote="true" max-items="3" >
18 </div>
19 <br/>
20 `val_url`
21 </div>
javascript:
1 //test controller
2 var test = function($scope) {
3 $scope.availableTags = [
4 "ActionScript",
5 "AppleScript",
6 "Asp",
7 "BASIC",
8 "C",
9 "C++",
10 "Clojure",
11 "COBOL",
12 "ColdFusion",
13 "Erlang",
14 "Fortran",
15 "Groovy",
16 "Haskell",
17 "Java",
18 "JavaScript",
19 "Lisp",
20 "Perl",
21 "PHP",
22 "Python",
23 "Ruby",
24 "Scala",
25 "Scheme"
26 ];
27
28 $scope.getsource = function(pattern, response) {
29 response($scope.availableTags);
30 };
31 $scope.change = function() {
32 console.log('change', $scope.val_Array);
33 };
34 };
35
36 appMoule.controller("Test", test);
37 //mock ajax.
38 var oldAjax = jQuery.ajax;
39 jQuery.ajax = function(param) {
40 if (param.url === "url") {
41 var term = param.data.term;
42 param.success([term + "1", term + "2", 3 + term, 4 + term]);
43 }
44 else {
45 oldAjax(param);
46 }
47 };
48
49 //jQuery.ajax({url:"text.html"}); must erroe:GET http://fiddle.jshell.net/_display/text.html 404 (NOT FOUND)
在測試中為了驗證url,本想通過自己的博客導入json數據,但是跨域等問題,所以沒辦法,在最后選擇了mock jQuery.Ajax,本想引入jasmine測試框架利用spyOn(jasmine測試mock文檔:
http://pivotal.github.com/jasmine/jsdoc/symbols/jasmine.Spy.html),但是找了很久沒找到在線引用包。最后采用手動血mock代碼如下:
1 //mock ajax.
2 var oldAjax = jQuery.ajax;
3 jQuery.ajax = function(param) {
4 if (param.url === "url") {
5 var term = param.data.term;
6 param.success([term + "1", term + "2", 3 + term, 4 + term]);
7 }
8 else {
9 oldAjax(param);
10 }
11 };
所以你看見的第三個返回值永遠會是輸入前綴加1,2,3.
測試第一輸入框測試scope屬性,第二測試scope函數(有兩個輸入參數),第三測試url ajax。