Twitter Bootstrap的typeahead:使用`this`获取上下文或调用元素

19

我正在使用Twitter Bootstrap 2.1.1的Typeahead组件以及jQuery 1.8.1。

我正在尝试从typeahead的updater函数中访问文本框元素。这是我的当前代码,它运行得很好:

$('#client-search').typeahead({
    source: function (query, process) {
        $.get(url, { query: query }, function (data) {
            labels = [];
            mapped = {};
            $.each(data, function(i,item) {
                mapped[item.label] = item.value;
                labels.push(item.label);
            });
            process(labels);
        });
    }
    ,updater: function (item) {
        $('#client-id').val(mapped[item]);
        return item;
    }
    ,items: 10
    ,minLength: 2
});

我在同一个页面上有很多输入搜索框,每个搜索框都有一个ID #xxx-search,并对应一个隐含的ID为#xxx-id的输入框。我想通过以下方式重复使用相同的代码:

$('#client-search, #endClient-search, #other-search').typeahead({

    ...

    ,updater: function (item) {
        var target = $(this).attr('id').split('-')[0] + '-id';
        $('#'+target).val(mapped[item]);
        return item;
    }

    ...

我曾认为this指的是当前正在使用的文本框元素,但显然不是这样,因为在Firebug中我收到了未定义错误:

$(this).attr("id") is undefined

当我使用this而不是$(this)时,我会得到:

this.attr is not a function

有人能帮我使这个工作起来吗?


更新:答案以及更多内容!

感谢benedict_w在下面的回答,现在不仅这个可以完美运行,而且我还改进了它的可重用性。

这是我的看起来像:

<input type="text" autocomplete="off"
    id="client-search"
    data-typeahead-url="/path/to/json"
    data-typeahead-target="client-id">
<input type="hidden" id="client-id" name="client-id">

注意搜索框是如何引用隐藏的id的。这是新的JS代码:

$(':input[data-typeahead-url]').each(function(){
    var $this = $(this);
    $this.typeahead({
        source: function (query, process) {
            $.get($this.attr('data-typeahead-url'), { query: query }, function (data) {
                labels = [];
                mapped = {};
                $.each(data, function(i,item) {
                    mapped[item.label] = item.value;
                    labels.push(item.label);
                });
                process(labels);
            });
        }
        ,updater: function (item) {
            $('#'+$this.attr('data-typeahead-target')).val(mapped[item]);
            return item;
        }
        ,items: 10
        ,minLength: 2
    });
});

当我使用这个解决方案时,在下拉菜单中出现了“未定义”的选项。 - Xeoncross
@Xeoncross:自从这个问题被发布以来,Bootstrap和jQuery已经更新了多次。它可能不再适用于您正在使用的版本。 - Peter Di Cecco
2个回答

24

您正在内部函数中,因此您需要在外部闭包中保存对元素的引用,然后将其传递给内部闭包的事件处理程序。您可以使用一个 $.each() 调用来循环遍历选择器并保存对元素的引用(this)- 例如:

$('#client-search, #endClient-search, #other-search').each(function() {
    var $this = $(this);
    $this.typeahead({
        ...

        ,updater: function (item) {
            var target = $this.attr('id').split('-')[0] + '-id';
            $('#'+target).val(mapped[item]);
            return item;
        }
        ...
     });

你可以在这里找到更多关于JavaScript闭包的讨论:https://dev59.com/6XVD5IYBdhLWcg3wBm5h - benedict_w
我为这个问题苦苦挣扎了两个小时。你救了我的一天! - nizam.sp

6
接受的答案很好,但是我想分享一个不需要外部封闭的替代方法。我正在使用bootstrap v2.3.1,你可以从this.$element获得输入内容。
例如:
$(':input[data-typeahead-url]').typeahead({
    source: function (query, process) {
        $.get(this.$element.attr('data-typeahead-url'), { query: query }, function (data) {
            labels = [];
            mapped = {};
            $.each(data, function(i,item) {
                mapped[item.label] = item.value;
                labels.push(item.label);
            });
            process(labels);
        });
    }
    ,updater: function (item) {
        $('#'+this.$element.attr('data-typeahead-target')).val(mapped[item]);
        return item;
    }
    ,items: 10
    ,minLength: 2
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接