53

I am using Angular-UI typeahead in the following way:

<input type="text" ng-model="myModel" typeahead="o.value as o.text for o in options | filter:$viewValue | limitTo:5" typeahead-editable="false" />

binded to a model like:

var options = [
    {"value": 1, "text": "value1"},
    {"value": 2, "text": "value2"},
    ...
];

It correctly shows options text, but when I select an item it shows inside the textbox the value. The model is correctly bounded to the value only (not the entire model object).

Is it possible to show inside the textbox the "text" (not the "value") after selection, still maintaining model binding to just the value (ie: when I select a certain "text" the model is updated with the "value")?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Matteo Piazza
  • 2,462
  • 7
  • 29
  • 38
  • 1
    Could you not use typeahead-on-select to set the selected value. Remove "o.value as" from type ahead. – epitka Dec 17 '13 at 15:29

6 Answers6

53

It's not ideal, but the typeahead-input-formatter attribute provides a work-around until a fix can be provided. (Plunker from github thread).

HTML:

<input type="text" 
       ng-model="myModel" 
       typeahead="o.value as o.text for o in options | filter:$viewValue | limitTo:5" 
       typeahead-editable="false" 
       typeahead-input-formatter="formatLabel($model)" 
/>

AngularJs controller function:

$scope.formatLabel = function(model) {
   for (var i=0; i< $scope.options.length; i++) {
     if (model === $scope.options[i].value) {
       return $scope.options[i].text;
     }
   }
};
krimhorn
  • 531
  • 4
  • 3
  • 25
    Note: If you have a simpler formatting task, like accessing an attribute of the model, you can just do `typeahead-input-formatter="$model.firstName + ' ' + $model.lastName"`. – Nick Merrill Jun 17 '14 at 14:50
  • And you can use Angular built in function to iterate through a collection or array: `angular.forEach` https://docs.angularjs.org/api/ng/function/angular.forEach – zelibobla Dec 19 '14 at 07:11
  • 2
    @NickM that won't work if you're using `o.value as o.text` syntax as the `$model` value reflects the parsed value of `o.value`, in this case a simple string – jusopi Jun 12 '15 at 15:24
  • Hello, Did you able to make this work with Ajax source? Here is the [GitHub bug report](https://github.com/angular-ui/bootstrap/issues/2160) – Murali Murugesan Aug 09 '15 at 19:02
  • @NickM this keeps white space in input control – Yehia Dec 31 '15 at 18:56
  • 4
    Unfortunately, this workaround doesn't work if you're populating the typeahead asynchronously. – Paul Taylor Jan 26 '16 at 18:52
  • @NickMerrill @jusopi for this you should use only `o` and not `o.value`. @yehia use `typeahead-input-formatter="$model && ...` for keeping input clear when no value – Bernardo Dal Corno Feb 15 '19 at 17:12
28

Try changing your code from

typeahead="o.value as o.text for o in options | filter:$viewValue | limitTo:5"

to

typeahead="o as o.text for o in options | filter:$viewValue | limitTo:5"
ConcurrentHashMap
  • 4,998
  • 7
  • 44
  • 53
UmaKiran
  • 440
  • 4
  • 11
10

You can try doing as suggested but with typeahead-on-select like so

<input type="text" 
       ng-model="myModel" 
       typeahead="o as o.text for o in options | filter:$viewValue | limitTo:5" 
       typeahead-editable="false" 
       typeahead-on-select="model=$item.value"
/>

This will ensure that the text or label is displayed but underlying value is changed.

domenicr
  • 352
  • 3
  • 14
  • this makes the assumption that you can be somewhat free to choose the format you `ng-model` will use. When restricted to simple types as in `ng-model="item.value", this will not work unless you proxy it somehow. – jusopi Jun 12 '15 at 15:22
  • You should mention that `model` is not some what the as `myModel`. I use your method but `model` mean bind to the `new model` and used it in the controller. somehow the ng-model is still the object format. – praHoc Oct 16 '17 at 07:43
3

Here a shorthand formatter for everybody who uses lodash or underscore:

function formatTypehead(array,id){
  var o = _.find(array,{id:id});
  return (o?o.displayName || id:id);
}

and html:

<input  type="text" 
  uib-typeahead="s.id as s.displayName for s in companies | filter:$viewValue | limitTo:8"
  typeahead-input-formatter="formatTypehead(companies, $model)"
  ng-model="model.company"
  >
Simon Fakir
  • 1,712
  • 19
  • 20
1

Well, so far I found a possible solution through directives.

HTML

<div my-autocomplete my-autocomplete-source="element" my-autocomplete-model="obj[element.model]"></div>

DIRECTIVE

app.directive('myAutocomplete', function() {
    return {    
        restrict: 'A',
        replace: true,
        template: '<input type="text" name="{{myAutocompleteSource.model}}" placeholder="{{myAutocompleteSource.label}}" ng-model="selected" typeahead="o as o.text for o in myAutocompleteSource.options | filter:$viewValue | limitTo:5" typeahead-editable="false" />',
        scope: {
            myAutocompleteSource: '=',
            myAutocompleteModel: '='
        },
        controller: function($scope) {
            $scope.selected = null;
            $scope.$watch('selected', function() { 
                $scope.myAutocompleteModel = ($scope.selected && 'value' in $scope.selected) ? $scope.selected.value : null; 
            });
        }
    };  
});

Well... obviously this is only a trick... I would like to know if is there a cleaner, more natural way to do it... without modifying code or using directive...

Matteo Piazza
  • 2,462
  • 7
  • 29
  • 38
0

for me this:

uib-typeahead="o as o.RagioneSociale for o in main.getLocation($viewValue)"

instead of:

typeahead="o as o.RagioneSociale for o in main.getLocation($viewValue)"

was really usefull

i had a json made like this:

[{"RagioneSociale":"Politi Real Estate sas","IDAnagrafica":"2516"},{"RagioneSociale":"COND METROPOLITAN","IDAnagrafica":"4325"}]


Model: {{asyncSelected | json}}
<input type="text" ng-model="asyncSelected" uib-typeahead="o as o.RagioneSociale for o in main.getLocation($viewValue)" typeahead-loading="loadingLocations" typeahead-no-results="noResults" class="form-control">

and it ended up in something like having the dropdown menu with just the RagioneSociale value and a model where i can see both the text and the id and print them with a normal {{asyncSelected}}

Gio Venice
  • 55
  • 8