用AngularJS创建一个预输入插件
发布在用Angular开发web应用2014年3月3日view:11845
在文章任何区域双击击即可给文章添加【评注】!浮到评注点上可以查看详情。

如果你开始编写一个AngularJS项目的话,你可能想要让所有的组件都使用Angular来编写。尽管我们也可以使用一些现有的jQuery插件,但是将一大堆jQuery代码放入到一个指令中并不是我们的最佳选择。我们应该首先来想想看我们想要的功能是否能使用纯Angular来实现,这是一种更好的方式。这让我们的应用代码更简洁并且更具可维护性。在本文中,我们将学习如何使用AngularJS来创建一个简单的预输入插件。

概要

在本文中我们将要学着创建一个简单地预输入插件,当用户在一个文本框中输入东西时它会显示一些提示。我们想要达成的目标是我们的插件可以配置并能轻松运用到已存在的系统中。基本的步骤有以下几步:

  • 创建一个factory service来和一个RESTful API进行交互,并返回JSON用于自动生成提示
  • 创建一个指令来使用JSON数据并封装预输入input字段
  • 让指令可配置以便用户可以根据自己的需求进行配置

配置选项

  1. 准确的JSON对象属性来作为提示的一部分
  2. 控制器scope中的模型来存储选中的项目
  3. 控制器中的函数,它在一个项目被选中时执行
  4. 预输入input字段中的一段占位符文本

第一步:创建一个Factory来获取数据

作为第一步,我们先使用Angular中的$http service来和RESTful API进行交互。我们来看看下面的这段代码:

var typeAhead = angular.module('app',[]);

typeAhead.factory('dataFactory',function($http){
    return {
        get: function(url){
            return $http.get(url).then(function(reap){
                return reap.data; //成功回调则返回这个
            });
        }
    };
});   

上面的代码创建了一个叫做dataFactory的factoet,它将从一个API获取数据。在这里我们不会讲述关于factory的细节,但是我们需要稍稍了解一些$http。你为get()函数传递了一个URL,它将返回一个promise。接着我们在这个promise上调用then(),它将返回另一个promise。这个promise如果成功则使用then()中的函数进行解析。因此,在我们的控制器中,我们不直接与$http进行交互。相反,我们在控制器中使用一个factory的实例,并为get()函数传递一个URL。因此,我们的控制器与factory互动的代码如下所示:

typeAhead.controller('TypeAheadController',function($scope,dataFactory){
    dataFactory.get('states.json').then(function(data){
        $scope.items = data;
    });
    $scope.name = '';//这一项将用来保存选中的项目   
    $scope.onItemSelected = function(){
        console.log('selected=' + $scope.name);
    };
});  

上面的代码使用一个叫做states.json的API节点来返回一个美国各州的JSON列表。当数据可用时,我们会在$scope的items模型中存储这个列表。我们也使用模型name来保存选中的项目。最后,函数onItemSelected()会在用户选中某一个州时执行。

第二步:创建一个指令

我们现在来创建typeAhead指令,代码如下所示:

typeAhead.directive('typeahead',function($timeout){
    return {
        restrict: 'ACE',
        scope: {
            items: '=',
            prompt: '@',
            title: '@',
            subtitle: '@',
            model: '=',
            onSelect: '&'
        },
        link: function(scope,elem,attrs){

        },
        template: 'templates/templateurl.html'
    };
});

在指令中我们创建了一个隔离scope来定义一些属性:

  • items: 用来给隔离scope传递JSON列表
  • prompt:单向绑定用来传递typeahead输入字段的占位符文本
  • title和subtitle: 每一个完整的字段都有title和subtitle。大多数的预输入插件都采用这种方式。在这里的例子中title代表州名,而subtitle代表简写
  • model: 双向绑定用来存储选择项
  • onSelect: 方法绑定,用来在选择结束之后执行控制器scope中的函数

注意:一个示例JSON返回的数据如下所示:

{
    "name": "Alabama",
    "abbreviation": "AL"
}

第三步:创建模板

现在,我们来创建在指令中需要用到的模板:

<input type="text" ng-model="model" placeholder="{{prompt}}" ng-keydown="selected=false"/>   

<div class='items' ng-hide='!model.length || selected'>
    <div class='item' ng-repeat="item in items | filter:model track by $index" ng-click="handleSelection(item[title])" style="cursor:pointer" ng-class="{active:isCurrent($index)}" ng-mouseenter="setCurrent($index)">  
      <p class='title'>{{item[title]}}</p>
      <p class='subtitle'>{{item[subltitle]}}</p>
    </div>
</div>    

首先,我们渲染了一个input字段来让用户输入。scope的属性prompt被赋值给了placeholder属性。接着,我们循环了州列表来显示name和abbreviation属性。这些属性通过title和subtitle属性来配置。指令ng-mouseenter和ng-class被用来当用户移入鼠标时高亮选项。接着,我们使用filter:model来通过文本输入过滤列表。最后,我们使用ng-hide指令来隐藏列表,如果input文本字段为空或者用户选中了一个想。这个selected属性在handleSelection()函数中被设置为true,然后在用户开始在input字段中输入时被设置为false。

第四步:更新link函数

接下来,我们要更新指令中的link函数:

link: function(scope,elem,attrs){
    scope.handleSelection = function(selectedItem){
        scope.model = selectedItem;
        scope.current = 0;
        scope.selected = true;
        $timeout(function(){
            scope.onSelect();
        },200);
    };
    scope.current = 0;
    scope.selected = true;//开始时隐藏列表
    scope.isCurrent = function(index){
        return scope.current == index;
    };
    scope.setCurrent = function(index){
        scope.current = index;
    };
}

函数handleSelection()用来更新scope的属性model。接着,我们重置了current和selected属性。然后,我们调用onSelect()函数。在这里我们添加了一个延时因为scope.model=selecteditem赋值并不会马上更行绑定的控制器属性。在模型被选中的项目更新之后控制器scope回调函数将会被执行。这就是我们要使用一个$timeout service的原因。

另外,函数isCurrent()和setCurrent()一起用来高亮项目。下面的CSS也被用来完成这个高亮的过程:

.active {
  background-color: #C44741;
  color: #f2f2f2;
}

第五步:配置并使用指令

最后,我们在HTML中使用这个指令,代码如下所示:

<div class='container' ng-controller='TypeAheadController'>
    <h1>TypeAhead Using AngularJS</h1>
    <typeahead items='items' prompt='Satrt typing a US state' subtitle='abbreviation' model='name' on-select='onItemSelected()'/>
</div>  

本文译自creating a typeahead widget with angularjs,原文地址http://www.sitepoint.com/creating-a-typeahead-widget-with-angularjs/

如果你觉得本文对你有帮助,请点击为我提供赞助

评论
发表评论
4年前
添加了一枚【评注】:RESTful
WRITTEN BY
张小俊128
Intern in Baidu mobile search department。认真工作,努力钻研,期待未来更多可能。
TA的新浪微博
PUBLISHED IN
用Angular开发web应用

讲述Angular开发框架的基础知识,帮助读者快速学习并深入理解Angular的开发理念和具体应用方式

我的收藏