冠军

导航

在 angularjs 中集成 bootstrap typeahead

问题

在使用 typeahead 的时候,有这样一个需求,当用户选中其中一项的之后,将项目对应的 id 保存到另外一个变量中,以后在提交表单的时候,将这个 id 发送到服务器中。

但是,在 typeahead 中对于元素的操作,angularjs 没有感知到,导致不能获取最新的数据。

typeahead 中选择数据之后的事件 itemSelected

在 typeahead 中,我们可以定义一个 itemSelected 的事件处理函数,在选中一个项目之后, typeahead 会触发这个事件,我们在这个事件中可以获取当前选中的元素,对应的值,已经显示的提示文本。

这个函数的使用方式如下:

itemSelected: function (item, val, text) {
        console.info(val);
}

集成到页面中,我们可以如下配置 typeahead 的配置参数。

var option = {
    ajax: {
        url: '@Url.Action("AjaxService")',
        timeout: 300,
        method: "post",
        triggerLength: 3,
        preDispatch: function (query) {
            return { type: type, query: query };
        },
        preProcess: function (data) {
            return data;
        }
    },
    display: "name",
    val: "id",
    itemSelected: function (item, val, text) {
        console.info(item);
    }
};
$("#tbxName").typeahead(option);

但是,在使用 angularjs 的时候,会带来一个问题,如果我们直接将这个 id 赋予某个元素,比如说输入框的话,angularjs 是不能检测到这个元素值的变化的,angularjs 通过监测元素的获取焦点,失去焦点,change 等事件来感知输入元素的变化,在通过代码直接赋值的时候,会没有这些事件的触发。

原理

我们可以通过 angularjs 的自定义指令将 typeahead 封装一下,在 itemSelected 事件触发的时候,调用 angularjs 的 $apply 发出通知,这样 angularjs 自然就可以感知到数据的变化了。

实现

为了便于已经熟悉 typeahead 的朋友,继续使用原来的方式进行配置,我们不修改配置方式。

指令的定义如下:

// 自定义指令
app.directive("typeahead", function () {
    var option = {
        restrict: "A",
        require: "?ngModel",
        scope:  {
            option: "=typeahead"
        },
        link: function (scope, element, attrs, ngModel) {

            // typeahead 的配置参数
            var option = scope.option;

            // 将原来的 itemSelected 替换为 angularjs 的 itemSelected 函数
            // 在用户选择了选项之后,通过 angularjs 执行
            var itemSelected = option.itemSelected;
            option.itemSelected = function (item, val, text) {
                scope.$apply(function () {
                    itemSelected(item, val, text);
                })
            };

            element.typeahead(option);
        }
    };
    return option;
});

scope 是自定义一个作用域,=typeahead 是将 typeahead 属性的值取过来,剩下的处理就比较简单了,我们将原来的 itemSelected 事件截获过来,通过 scope.$apply 进行处理,这样 angularjs 自然就可以获取数据的变化了。

元素的定义如下,增加一个名为 typeahead 的 Attribute, 值就是配置参数对象,定义在 angularjs 的模型对象上。

<input typeahead ="typeaheadOption" ng-model="petName" type="text" />

下面是对应的脚本。

// 控制器
app.controller("myController", function ($scope) {
// 额外附加的参数
    $scope.type = "java";

    // 标准的使用方式
    $scope.petName = "Cat";
    $scope.petId = "";

    // 使用标准的 typeahead 配置参数, 在元素上使用 typeahead Attribute 连接
    $scope.typeaheadOption
        = {
            ajax: {
                url: '@Url.Action("AjaxService")',
                timeout: 300,
                method: "post",
                triggerLength: 3,
                preDispatch: function (query) {
                    return { type: $scope.type, query: query };
                },
                preProcess: function (data) {
                    return data;
                }
            },
            display: "name",
            val: "id",
            itemSelected: function (item, val, text) {
                $scope.petId = val;
            }
        };

});

总结

使用 angularjs 的自定义指令,我们可以很容易地将 angularjs 之外的事件处理封装到 angularjs 之中。

 

 

posted on 2014-03-09 22:54  冠军  阅读(7625)  评论(2编辑  收藏  举报