在前几篇随笔简单介绍了AngularJS,在AngularJS 指令(directive)是重要的概念,主要负责了很大部分的组建样式交互。在前面介绍过directive需要预先的模板编译在返回一个link的函数,注册行为事件交互等等。在这里不多说了,关于指令的介绍将在后续一并补上。在这里我们先看一个利用jQuery UI组件开发的AngularJS Autocomplete指令。
代码:
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文档:
),但是找了很久没找到在线引用包。最后采用手动血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。