Html 在 AngularJS 的选择下拉列表中添加搜索过滤器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25550462/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 02:35:45  来源:igfitidea点击:

Add search filter inside the select dropdown in AngularJS

htmlangularjs

提问by Vaibhav Pachauri

I want to add a search filter inside a select dropdown in angularJS.

我想在 angularJS 的选择下拉列表中添加一个搜索过滤器。

I have used ng-options to list down the options and used filter to filter out the data in the search box , but the problem is that the search box is not coming inside(or under) select dropdown. (When I click the select dropdown, it shows a search filter and below it has all the options)

我使用 ng-options 列出选项并使用 filter 过滤掉搜索框中的数据,但问题是搜索框没有进入(或低于)选择下拉列表。(当我点击选择下拉菜单时,它会显示一个搜索过滤器,它下面有所有选项)

Below is the code for your reference :

以下是供您参考的代码:

<div class="rowMargin">
<label class="control-label" for="entitySel">Entity:</label>
<div class="controls">
    <select id="entityId" class="input-medium" type="text" name="entityId" ng-model="payment.entityId" ng-options="entityOpt for entityOpt in paymentEntityOptions">
        <option value="">Select</option>
    </select>
    <span ng-show=" submitted && addPayment.entityId.$error.required">
        <label class="error">Please provide entity Id </label>
    </span>
    <div ng-show="payment.entityId == \'Individual\'">
        <span>
            <select ng-model="payment.entity.individual" ng-options = "individual for individual in individualEntities | filter : filterEntity">
                <option value="">Select Individual Entity</option>
                <option>
                    <input type="search" placeholder="Search" ng-model="filterEntity"></input>
                </option>
            </select>
        </span>
    </div>
    <div ng-show="payment.entityId == \'Group\'">
        <span>
            <select ng-model="payment.entity.group" ng-options = "group for group in groupEntities | filter : filterEntity">
                <option value="">Select Group Entity</option>
                <input type="search" placeholder="Search" ng-model="filterEntity"></input>
            </select>
        </span>
    </div>
</div>

采纳答案by Vaibhav Pachauri

I have used the bootstrap button with class 'dropdown-toggle' and on click of the button I have appended an input search box as following :

我使用了带有“下拉切换”类的引导按钮,单击该按钮后,我附加了一个输入搜索框,如下所示:

<div class="dropdown pull-right makePaymentDropdownMainDiv" auto-close="outsideClick">
<button class="btn btn-default dropdown-toggle makePaymentDropdownBtn" type="button" id="individualDrop" data-toggle="dropdown">{{payment.entity}}<span class="caret pull-right"></span></button>
<span ng-show="submitted"><label class="error">Select an Individual</label></span>
<ul class="dropdown-menu makePaymentDropdownUlStyle" role="menu" aria-labelledby="individualDrop">
    <input disable-auto-close type="search" ng-model="serchFilter" class="makePaymentDropdownSearchBox" placeholder="Search"></input>
    <li role="presentation" ng-repeat="indi in individuals | filter: serchFilter"><a role="menuitem" ng-click="selectEntity(indi)">{{indi}}</a></li>  
</ul>
</div>

Showing the 'li' using ng-repeat.

使用 ng-repeat 显示“li”。

Remember to add auto-close="outsideClick" to your dropdown so that it doesn't close on filtering attempt.

请记住将 auto-close="outsideClick" 添加到您的下拉列表中,这样它就不会在过滤尝试时关闭。

回答by dirkjot

Sorry, I'm rather late to the party, but to me it sounds like you need acute-select, an open source extension (MIT license) to Angular that does exactly this, without further dependencies.

抱歉,我参加聚会有点晚了,但对我来说,这听起来像是需要Acute-select,这是 Angular 的开源扩展(MIT 许可证),它完全可以做到这一点,而无需进一步的依赖。

They also have a demo page, which shows what it can do nicely.

他们还有一个演示页面,展示了它可以很好地做什么。

回答by SantoshK

you can use easy and best way to search filter inside the select dropdown in AngularJS

您可以使用简单和最佳的方式在 AngularJS 的选择下拉列表中搜索过滤器

Working Demo : http://plnkr.co/edit/o767Mg6fQoyc7jKq77If?p=preview

工作演示:http: //plnkr.co/edit/o767Mg6fQoyc7jKq77If?p=preview

(function (angular, undefined) {
    'use strict';

    // TODO: Move to polyfill?
    if (!String.prototype.trim) {
        String.prototype.trim = function () {
            return this.replace(/^\s+|\s+$/g, '');
        };
    }

    /**
     * A replacement utility for internationalization very similar to sprintf.
     *
     * @param replace {mixed} The tokens to replace depends on type
     *  string: all instances of ##代码## will be replaced
     *  array: each instance of ##代码##, ,  etc. will be placed with each array item in corresponding order
     *  object: all attributes will be iterated through, with :key being replaced with its corresponding value
     * @return string
     *
     * @example: 'Hello :name, how are you :day'.format({ name:'John', day:'Today' })
     * @example: 'Records ##代码## to  out of  total'.format(['10', '20', '3000'])
     * @example: '##代码## agrees to all mentions ##代码## makes in the event that ##代码## hits a tree while ##代码## is driving drunk'.format('Bob')
     */
    function format(value, replace) {
        if (!value) {
            return value;
        }
        var target = value.toString();
        if (replace === undefined) {
            return target;
        }
        if (!angular.isArray(replace) && !angular.isObject(replace)) {
            return target.split('##代码##').join(replace);
        }
        var token = angular.isArray(replace) && '$' || ':';

        angular.forEach(replace, function (value, key) {
            target = target.split(token + key).join(value);
        });
        return target;
    }

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

    module.value('customSelectDefaults', {
        displayText: 'Select...',
        emptyListText: 'There are no items to display',
        emptySearchResultText: 'No results match "##代码##"',
        addText: 'Add',
        searchDelay: 300
    });

    module.directive('customSelect', ['$parse', '$compile', '$timeout', '$q', 'customSelectDefaults', function ($parse, $compile, $timeout, $q, baseOptions) {
        var CS_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?\s+for\s+(?:([$\w][$\w\d]*))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/;

        return {
            restrict: 'A',
            require: 'ngModel',
            link: function (scope, elem, attrs, controller) {
                var customSelect = attrs.customSelect;
                if (!customSelect) {
                    throw new Error('Expected custom-select attribute value.');
                }

                var match = customSelect.match(CS_OPTIONS_REGEXP);

                if (!match) {
                    throw new Error("Expected expression in form of " +
                        "'_select_ (as _label_)? for _value_ in _collection_[ track by _id_]'" +
                        " but got '" + customSelect + "'.");
                }

                elem.addClass('dropdown custom-select');

                // Ng-Options break down
                var displayFn = $parse(match[2] || match[1]),
                    valueName = match[3],
                    valueFn = $parse(match[2] ? match[1] : valueName),
                    values = match[4],
                    valuesFn = $parse(values),
                    track = match[5],
                    trackByExpr = track ? " track by " + track : "",
                    dependsOn = attrs.csDependsOn;

                var options = getOptions(),
                    timeoutHandle,
                    lastSearch = '',
                    focusedIndex = -1,
                        matchMap = {};

                var itemTemplate = elem.html().trim() || '{{' + (match[2] || match[1]) + '}}',

                    dropdownTemplate =
                    '<a class="dropdown-toggle" data-toggle="dropdown" href ng-class="{ disabled: disabled }">' +
                        '<span>{{displayText}}</span>' +
                        '<b></b>' +
                    '</a>' +
                    '<div class="dropdown-menu">' +
                        '<div stop-propagation="click" class="custom-select-search">' +
                            '<input class="' + attrs.selectClass + '" type="text" autocomplete="off" ng-model="searchTerm" />' +
                        '</div>' +
                        '<ul role="menu">' +
                            '<li role="presentation" ng-repeat="' + valueName + ' in matches' + trackByExpr + '">' +
                                '<a role="menuitem" tabindex="-1" href ng-click="select(' + valueName + ')">' +
                                    itemTemplate +
                                '</a>' +
                            '</li>' +
                            '<li ng-hide="matches.length" class="empty-result" stop-propagation="click">' +
                                '<em class="muted">' +
                                    '<span ng-hide="searchTerm">{{emptyListText}}</span>' +
                                    '<span class="word-break" ng-show="searchTerm">{{ format(emptySearchResultText, searchTerm) }}</span>' +
                                '</em>' +
                            '</li>' +
                        '</ul>' +
                        '<div class="custom-select-action">' +
                            (typeof options.onAdd === "function" ?
                            '<button type="button" class="btn btn-primary btn-block add-button" ng-click="add()">{{addText}}</button>' : '') +
                        '</div>' +
                    '</div>';

                // Clear element contents
                elem.empty();

                // Create dropdown element
                var dropdownElement = angular.element(dropdownTemplate),
                    anchorElement = dropdownElement.eq(0).dropdown(),
                    inputElement = dropdownElement.eq(1).find(':text'),
                    ulElement = dropdownElement.eq(1).find('ul');

                // Create child scope for input and dropdown
                var childScope = scope.$new(true);
                configChildScope();

                // Click event handler to set initial values and focus when the dropdown is shown
                anchorElement.on('click', function (event) {
                    if (childScope.disabled) {
                        return;
                    }
                    childScope.$apply(function () {
                        lastSearch = '';
                        childScope.searchTerm = '';
                    });

                    focusedIndex = -1;
                    inputElement.focus();

                    // If filter is not async, perform search in case model changed
                    if (!options.async) {
                        getMatches('');
                    }
                });

                if (dependsOn) {
                    scope.$watch(dependsOn, function (newVal, oldVal) {
                        if (newVal !== oldVal) {
                            childScope.matches = [];
                            childScope.select(undefined);
                        }
                    });
                }

                // Event handler for key press (when the user types a character while focus is on the anchor element)
                anchorElement.on('keypress', function (event) {
                    if (!(event.altKey || event.ctrlKey)) {
                        anchorElement.click();
                    }
                });

                // Event handler for Esc, Enter, Tab and Down keys on input search
                inputElement.on('keydown', function (event) {
                    if (!/(13|27|40|^9$)/.test(event.keyCode)) return;
                    event.preventDefault();
                    event.stopPropagation();

                    switch (event.keyCode) {
                        case 27: // Esc
                            anchorElement.dropdown('toggle');
                            break;
                        case 13: // Enter
                            selectFromInput();
                            break;
                        case 40: // Down
                            focusFirst();
                            break;
                        case 9:// Tab
                            anchorElement.dropdown('toggle');
                            break;
                    }
                });

                // Event handler for Up and Down keys on dropdown menu
                ulElement.on('keydown', function (event) {
                    if (!/(38|40)/.test(event.keyCode)) return;
                    event.preventDefault();
                    event.stopPropagation();

                    var items = ulElement.find('li > a');

                    if (!items.length) return;
                    if (event.keyCode == 38) focusedIndex--;                                    // up
                    if (event.keyCode == 40 && focusedIndex < items.length - 1) focusedIndex++; // down
                    //if (!~focusedIndex) focusedIndex = 0;

                    if (focusedIndex >= 0) {
                        items.eq(focusedIndex)
                            .focus();
                    } else {
                        focusedIndex = -1;
                        inputElement.focus();
                    }
                });

                resetMatches();

                // Compile template against child scope
                $compile(dropdownElement)(childScope);
                elem.append(dropdownElement);

                // When model changes outside of the control, update the display text
                controller.$render = function () {
                    setDisplayText();
                };

                // Watch for changes in the default display text
                childScope.$watch(getDisplayText, setDisplayText);

                childScope.$watch(function () { return elem.attr('disabled'); }, function (value) {
                    childScope.disabled = value;
                });

                childScope.$watch('searchTerm', function (newValue) {
                    if (timeoutHandle) {
                        $timeout.cancel(timeoutHandle);
                    }

                    var term = (newValue || '').trim();
                    timeoutHandle = $timeout(function () {
                        getMatches(term);
                    },
                    // If empty string, do not delay
                    (term && options.searchDelay) || 0);
                });

                // Support for autofocus
                if ('autofocus' in attrs) {
                    anchorElement.focus();
                }

                var needsDisplayText;
                function setDisplayText() {
                    var locals = { };
                    locals[valueName] = controller.$modelValue;
                    var text = displayFn(scope, locals);

                    if (text === undefined) {
                        var map = matchMap[hashKey(controller.$modelValue)];
                        if (map) {
                            text = map.label;
                        }
                    }

                    needsDisplayText = !text;
                    childScope.displayText = text || options.displayText;
                }

                function getOptions() {
                    return angular.extend({}, baseOptions, scope.$eval(attrs.customSelectOptions));
                }

                function getDisplayText() {
                    options = getOptions();
                    return options.displayText;
                }

                function focusFirst() {
                    var opts = ulElement.find('li > a');
                    if (opts.length > 0) {
                        focusedIndex = 0;
                        opts.eq(0).focus();
                    }
                }

                // Selects the first element on the list when the user presses Enter inside the search input
                function selectFromInput() {
                    var opts = ulElement.find('li > a');
                    if (opts.length > 0) {
                        var ngRepeatItem = opts.eq(0).scope();
                        var item = ngRepeatItem[valueName];
                        childScope.$apply(function () {
                            childScope.select(item);
                        });
                        anchorElement.dropdown('toggle');
                    }
                }

                function getMatches(searchTerm) {
                    var locals = { $searchTerm: searchTerm }
                    $q.when(valuesFn(scope, locals)).then(function (matches) {
                        if (!matches) return;

                        if (searchTerm === inputElement.val().trim()/* && hasFocus*/) {
                            matchMap = {};
                            childScope.matches.length = 0;
                            for (var i = 0; i < matches.length; i++) {
                                locals[valueName] = matches[i];
                                var value = valueFn(scope, locals),
                                    label = displayFn(scope, locals);

                                matchMap[hashKey(value)] = {
                                    value: value,
                                    label: label/*,
                                    model: matches[i]*/
                                };

                                childScope.matches.push(matches[i]);
                            }
                            //childScope.matches = matches;
                        }

                        if (needsDisplayText) setDisplayText();
                    }, function() {
                        resetMatches();
                    });
                }

                function resetMatches() {
                    childScope.matches = [];
                    focusedIndex = -1;
                };

                function configChildScope() {
                    childScope.addText = options.addText;
                    childScope.emptySearchResultText = options.emptySearchResultText;
                    childScope.emptyListText = options.emptyListText;

                    childScope.select = function (item) {
                        var locals = {};
                        locals[valueName] = item;
                        var value = valueFn(childScope, locals);
                        //setDisplayText(displayFn(scope, locals));
                        childScope.displayText = displayFn(childScope, locals) || options.displayText;
                        controller.$setViewValue(value);

                        anchorElement.focus();

                        typeof options.onSelect === "function" && options.onSelect(item);
                    };

                    childScope.add = function () {
                        $q.when(options.onAdd(), function (item) {
                            if (!item) return;

                            var locals = {};
                            locals[valueName] = item;
                            var value = valueFn(scope, locals),
                                label = displayFn(scope, locals);

                            matchMap[hashKey(value)] = {
                                value: value,
                                label: label/*,
                                    model: matches[i]*/
                            };

                            childScope.matches.push(item);
                            childScope.select(item);
                        });
                    };

                    childScope.format = format;

                    setDisplayText();
                }

                var current = 0;
                function hashKey(obj) {
                    if (obj === undefined) return 'undefined';

                    var objType = typeof obj,
                        key;

                    if (objType == 'object' && obj !== null) {
                        if (typeof (key = obj.$$hashKey) == 'function') {
                            // must invoke on object to keep the right this
                            key = obj.$$hashKey();
                        } else if (key === undefined) {
                            key = obj.$$hashKey = 'cs-' + (current++);
                        }
                    } else {
                        key = obj;
                    }

                    return objType + ':' + key;
                }
            }
        };
    }]);

    module.directive('stopPropagation', function () {
        return {
            restrict: 'A',
            link: function (scope, elem, attrs, ctrl) {
                var events = attrs['stopPropagation'];
                elem.bind(events, function (event) {
                    event.stopPropagation();
                });
            }
        };
    });
})(angular);

<body ng-app="Demo">
        <div class="container" ng-controller="DemoController">
            <label>Level 1</label>
            <div custom-select="g for g in nestedItemsLevel1 | filter: $searchTerm" custom-select-options="level1Options" ng-model="level1"></div>
            <label>Level 2</label>
            <div custom-select="g for g in nestedItemsLevel2 | filter: $searchTerm" ng-model="level2" cs-depends-on="level1"></div>
        </div>
        <!-- basic scripts -->

        <!--[if !IE]> -->

        <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
        <!-- <![endif]-->

        <!--[if IE]>
        <script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
        <![endif]-->

        <script src="http://maxcdn.bootstrapcdn.com/bootstrap/2.3.2/js/bootstrap.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
        <script src="js/customSelect.js"></script>
            <script>
                (function () {
                    var app = angular.module('Demo', ['AxelSoft']);

                    app.controller('DemoController', ['$scope', '$timeout', '$q', function ($scope, $timeout, $q) {
                        $scope.searchAsync = function (term) {
                                // No search term: return initial items
                            if (!term) {
                                return  ['Item 1', 'Item 2', 'Item 3'];
                            }
                            var deferred = $q.defer();
                            $timeout(function () {
                                var result = [];
                                for (var i = 1; i <= 3; i++)
                                {
                                    result.push(term + ' ' + i);
                                }
                                deferred.resolve(result);
                            }, 300);
                            return deferred.promise;
                        };
                        $scope.nestedItemsLevel1 = ['Item 1', 'Item 2', 'Item 3'];
                        $scope.level1 = $scope.nestedItemsLevel1[0];
                        $scope.level1Options = {
                            onSelect: function (item) {
                                var items = [];
                                for (var i = 1; i <= 5; i++) {
                                    items.push(item + ': ' + 'Nested ' + i);
                                }
                                $scope.nestedItemsLevel2 = items;
                            }
                        };
                        $scope.nestedItemsLevel2 = [];
                        $scope.level1Options.onSelect($scope.nestedItemsLevel1[0]);
                    }]);

                })();
            </script>
    </body>

回答by Bhoomtawath Plinsut

https://docs.angularjs.org/api/ng/directive/select

https://docs.angularjs.org/api/ng/directive/select

There can be only one hard coded in a ngOption.

在 ngOption 中只能有一个硬编码。