AngularJS BootstrapUI Typeahead with object & selection functionality

76,635

Solution 1

The typeahead directive from http://angular-ui.github.io/bootstrap/ is very, very flexible and there are many ways of achieving the desired functionality. I'm presenting 2 of them here.

Firstly, the typeahead directive uses syntax very similar to the AngularJS select directive. This gives you full control over a displayed label and the data bound as model value. So what you could do is to simply display address as a label and bind postcode to the selPcode directly:

<input type="text" ng-model="selPcode" typeahead="state.postcode as state.address for state in states | filter:$viewValue" typeahead-editable="false" />

The key here is the as part is in the typeahead expression: typeahead="state.postcode as state.address for state in states

Also, please note that I'm using the typeahead-editable="false" attribute to bind model only when a selection is made. A working jsFiddle here: http://jsfiddle.net/jLupa/

Another solution, if you really need to use a callback function is to use the typeahead-on-select attribute:

<input type="text"  typeahead-on-select="setPcode($item)" ng-model="selected" typeahead="state.address for state in states | filter:$viewValue" />

It allows you to specify a callback when a match is selected. A working fiddle here: http://jsfiddle.net/t8BV2/

As the last note: ng-change won't work here since it would react on any change in the input while you want to capture selection only. ng-click is not of much use either as it reacts on clicking on the input field and not the matches popup. On top of this it wouldn't react on selections made by using keayboard.

Solution 2

@pkozlowski-opensource 's great solution has one drawback: you can't initialise the typeahead from the ng-model property in this way, at least if you want it to display the item's description and not its code.

I found a way to solve this by configuring the typeahead like this:

<input type="text" ng-model="selected" typeahead="state as state.address for state in states | filter:$viewValue" />

This returns a state object to the model property which can be initialised by setting the value to the appropriate object:

    $scope.selected = {postcode:'M1',address:'Manchester'};

Working fiddle here: https://jsfiddle.net/0y3ntj4x/3/

I think this scenario is missing from the angular-bootstrap documentation for the typeahead.

Solution 3

I has a similar problem,

<input type="text" ng-model="select" typeahead="a as a.Value for a in countries | filter:{{ Value:$viewValue }} "class="form-control" typeahead-editable="false" >

{ Code: AL,ParentCode: null,Value: Albania,Id: 1206,Name: countries }

but dindt work, with the use of a service in this way

$scope.countries = []; _services.getcountries(function(result) { $scope.countries = result; });

and was solved with

$scope.countries = []; _services.getcountries(function(result) { $.each(result, function(i, o) { $scope.countries.push(o); }); });

I hope help somebody

Solution 4

Just wanted to add on to the answer provided by @pkozlowski.opensource - the behavior displayed in jsfiddle.net/jLupa no longer works with version 0.10.0 of the Angular's UI-Bootstrap. See here: jsfiddle.net/jLupa/87/ . The only change I made was updating to version 0.10.0, and you can see that both input boxes resolve to the postal code.

Share:
76,635
stampeder
Author by

stampeder

Updated on January 28, 2020

Comments

  • stampeder
    stampeder about 4 years

    I'm trying to implement a typeahead in Angular using http://angular-ui.github.io/bootstrap/, where the typeahead field displays full addresses but once clicked another field is populated with just the postcode for that address. I'm trying to use ng-change or ng-click for this, but without any success..

    http://jsfiddle.net/UxTBB/2/

    angular.module('myApp', ['ui.bootstrap'])
        .controller("mainCtrl", function ($scope) {
        $scope.selected = '';
        $scope.states = [{postcode:'B1',address:'Bull ring'},{postcode:'M1',address:'Manchester'}];
        $scope.setPcode = function(site) {
            $scope.selPcode = site.postcode;
            };
    });
    
    <div class="container">
        <div ng-controller="mainCtrl" class="row-fluid">
            <form class="row-fluid">
                <div class="container-fluid">
                    postcode <input type="text" ng-model="selPcode" />
                    typeahead <input type="text"  ng-change="setPcode(site)" ng-model="selected" typeahead="state.address for state in states | filter:$viewValue" />
                </div>
            </form>
        </div>
    </div>
    

    Any ideas?

  • stampeder
    stampeder almost 11 years
    Ok, great, thanks for that! Works fine now apart from I'm using: <input type="text" placeholder="Type to filter" ng-model="siteAPop" typeahead-editable="false" typeahead="site.postcode as site.name + ', ' + site.address + ', ' + site.town for site in sites | filter:\$viewValue " > and the field shows ' , ,' to start with, rather than my placeholder. Any ideas?
  • pkozlowski.opensource
    pkozlowski.opensource almost 11 years
    @stampeder I think that there might be a bug in the version 0.4.0 connected to the field displaying ` , ,`. It was corrected in master already and will be part of the next release. Feel free to raise an issue in github.com/angular-ui/bootstrap/issues?state=open to confirm
  • Meeker
    Meeker over 10 years
    In this example, how would you select a default value. When I set "setPcode" to "M1" in the controller the expected result would be for the field to be filled in with "Manchester"?????
  • Josh C.
    Josh C. about 10 years
    +2 for $item. I didn't see that in the documentation. I'm glad I found it on the interwebs.
  • Dhrumil Bhankhar
    Dhrumil Bhankhar about 10 years
    Thanks for the " typeahead-editable". I have seen your fiddle "jsfiddle.net/jLupa". I want model to be set with only valid set. In the fiddle it works fine when I type "a" in typeahead box & select something then model is set. But wait, what if I edit it now? I mean, I clear "Manchester" & type "b" then it should not reset the model until I select something. Right now, it resets the model! You can see the text-box is blank. Isn't it something like it should fire setter only for valid values?
  • user592419
    user592419 over 9 years
    Is there a way to blur the field after yielding a typeahead?
  • Blair Connolly
    Blair Connolly over 8 years
    Did you find a way to make this work on version 0.10.0? I am using version 0.8.0 (because I'm stuck on Bootstrap v2.3.2 on a legacy app) and having the same problem. Is there built in functionality I'm missing here, or am I going to have to write my own code to put the label back into the text box?
  • Ryan Knell
    Ryan Knell about 8 years
    I 'fixed' your one here. AngularUI actually got pretty smart and anything that has the select value will be what is displayed. Even after a page reload / coming back from the database. So this was what I was looking for. Anyway if you need a working example, check out this fiddle jsfiddle.net/jLupa/421 all I changed was the select statement to not choose postcode, and on the other box it is bound to the postcode.
  • Vahid Alimohamadi
    Vahid Alimohamadi almost 8 years
    Thanks for your great answer. So i tried to develop this to use auto generated inputs but it not works. hmmmm where is my mistake? jsfiddle.net/0y3ntj4x/10
  • Vishal
    Vishal over 7 years
    In your fiddle it works fine. But when I try to implement same thing it partially works. I can see the dropdown also by pressing tab I can select the item. But In dropdown, Items text is not shown. Also for each item height is near about 3px. Can you please tell me something about this problem?
  • Soldeplata Saketos
    Soldeplata Saketos over 5 years
    @VahidAlimohamadi I don't understand your question. You are pushing empty objects into the $scope.selecteds