0

Is it possible to select multiple values from angular ui bootstrap typeahead?

http://angular-ui.github.io/bootstrap/#/typeahead

2 Answers 2

1

Hi without changing the codebase probably not - you could try https://github.com/rayshan/ui-multiselect

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you @KieranRyan for replying. I saw your valuable code for multiselect. But we had already started using the ui-select for this written by angular-ui team. github.com/angular-ui/ui-select
0

I recently had the same requirement and was able to solve it by overriding the internal bootstrap implementation via an alternate popup-template. I created a new directive (multi-select-typeahead) to encapsulate the change.

The template uses an ng-init to pass the scope reference (of the typeahead popup directive) to the multi-select-typeahead directive. There the directive overrides the parent's scope. $scope.$parent in this case is the bootstrap typeahead directive itself. The custom directive provides a new implementation of select() which is called internally by angular bootstrap. The new implementation prevents the popup from closing and removes selected items from the list.

The alternate popup I provided is almost entirely the same as the default angular bootstrap typeahead template "uib/template/typeahead/typeahead-popup.html". The only modification was the addition of the ng-init which passes its scope to the multi-select-typeahead directive.

I'm sure if you are clever enough you could render the angular bootstrap default template by reference and inject the ng-init part, removing the duplicated bootstrap code. This would make the solution a bit more resilient to future angular bootstrap changes. That being said, the solution is already quite a hack and is prone to breaking in future major releases.

Hope this is useful to someone!

angular.module('typeahead.demo', [
    'ngAnimate',
    'ngSanitize',
    'ui.bootstrap'
]);

angular
    .module('typeahead.demo')
    .controller('TypeaheadDemo', TypeaheadDemo);

function TypeaheadDemo($scope) {
    $scope.addItem = addItem;
    $scope.itemApi = itemApi;

    $scope.items = [];

    function addItem(item) {
        $scope.items.push(item);
    }

    function itemApi() {
        return [
            { name: 'apple' },
            { name: 'orange' },
            { name: 'grape' }
        ];
    }
}

angular
    .module('typeahead.demo')
    .directive('multiSelectTypeahead', multiSelectTypeahead);

function multiSelectTypeahead() {
    return {
        templateUrl: 'multi-select-typeahead.html',
        scope: {
            searchApi: '&',
            displayNameField: '@',
            onSelect: '&',
            inputPlaceholder: '@?'
        },
        link: function ($scope) {
            var uibTypeaheadScope;

            $scope.initializeScope = initializeScope;

            $scope.$watch('isOpen', function (newValue) {
                if (!newValue) {
                    $scope.searchTerm = '';
                }
            });

            function initializeScope(typeaheadPopupScope) {
                uibTypeaheadScope = typeaheadPopupScope.$parent;
                uibTypeaheadScope.select = selectItem;
            }

            function selectItem(index, event) {
                var selectedItem = uibTypeaheadScope.matches[index].model;

                event.stopPropagation();
                if (event.type === 'click') {
                    event.target.blur();
                }
                uibTypeaheadScope.matches.splice(index, 1);
                $scope.onSelect({ item: selectedItem });
            }
        }
    };
}
<!doctype html>
<html ng-app="typeahead.demo">
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-animate.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-sanitize.js"></script>
    <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-2.5.0.js"></script>
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
  </head>
  
  
  <script type="text/ng-template" id="typeahead-search-results.html">
    <ul ng-init="$parent.$parent.initializeScope(this)"
        class="dropdown-menu"
        ng-show="isOpen() && !moveInProgress"
        ng-style="{ top: position().top + 'px', left: position().left + 'px' }"
        role="listbox"
        aria-hidden="{{ !isOpen() }}">
        <li class="uib-typeahead-match"
            ng-repeat="match in matches track by $index"
            ng-class="{ active: isActive($index) }"
            ng-mouseenter="selectActive($index)"
            ng-click="selectMatch($index, $event)"
            role="option"
            id="{{ ::match.id }}">
            <div uib-typeahead-match
                index="$index"
                match="match"
                query="query"
                template-url="templateUrl"></div>
        </li>
    </ul>
  </script>

  <script type="text/ng-template" id="multi-select-typeahead.html">
    <input type="text"
           placeholder="{{::inputPlaceholder}}"
           ng-model="searchTerm"
           ng-model-options="{debounce: 500}"
           uib-typeahead="result as result[displayNameField] for result in searchApi({ searchText: $viewValue })"
           typeahead-is-open="isOpen"
           class="form-control"
           typeahead-popup-template-url="typeahead-search-results.html" />
  </script>
  
  <body>

<div ng-controller="TypeaheadDemo" style="padding-top: 15px;">

    <multi-select-typeahead class="col-xs-6"
                            search-api="itemApi(searchText)"
                            display-name-field="name"
                            on-select="addItem(item)"
                            input-placeholder="Search Items...">
    </multi-select-typeahead>
    <div class="col-xs-6">
        <ul class="list-group">
            <li class="list-group-item" ng-repeat="item in items">
                {{ item.name }}
            </li>
        </ul>
    </div>

</div>

  </body>
</html>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.