Al Ex Tsm
Al Ex Tsm

Reputation: 2102

Angular typeahead response error

I am implementing an input which allow to select multiple values as tags. I am working with angular-ui-bootstrap-typeahead

The following example with dummy data works fine:

enter image description here

view:

<script type="text/ng-template" id="form_field_ref">
 <div class='container-fluid' ng-controller="typeHeadTestCtrl">
     <input type="text" ng-model="selected"  typeahead="x.formatted_address for x in dynamicSearch($viewValue, field.displayName)"  class="form-control" typeahead-on-select='onSelect($item, field)'>
 </div>
</script>

part of controller:

        $scope.getLocation = function(val) {
          return $http.get('http://maps.googleapis.com/maps/api/geocode/json', {
            params: {
              address: val,
              sensor: false
            }
          }).then(function(response){
            console.log(response);
            return response.data.results.map(function(item){
              console.log(item);
              //items attribute=> address_components, formatted_address, place_id....
              return item;

            });
          });
        };

But when I try to connect to my actual data I get the following error:

TypeError: Cannot read property 'length' of undefined
at ui-bootstrap-tpls.js:3637
at processQueue (angular.js:13170)
at angular.js:13186
at Scope.$eval (angular.js:14383)
at Scope.$digest (angular.js:14199)
at Scope.$apply (angular.js:14488)
at $$debounceViewValueCommit (angular.js:20944)
at $setViewValue (angular.js:20916)
at HTMLInputElement.listener (angular.js:19632)
at HTMLInputElement.eventHandler (angular.js:3011)

Here is the code that fails:

view:

 <input type="text" ng-model="selected"  typeahead="x.theVal for x in dynamicSearch($viewValue, field.displayName)"  class="form-control" typeahead-on-select='onSelect($item, field)'>

the parts of the controller:

dynamicSearch() prepares what data to request on call of getDbRefDocs():

        $scope.dynamicSearch = function(searchTerm, name) {
          var allowed = {};
          var classString = "";
          allowed = datamodel.classes[$routeParams.class].attribute[name].allowed;
          for (key in allowed){
            classString = classString +  key + "|";
          }
          //remove last pipeline
          classString = classString.slice(0, -1);
          $scope.getDbRefDocs(searchTerm, name, classString);
        };

        $scope.getDbRefDocs = function(searchTerm, name, classString) {
          var url = '/api/v2/docs/' + classString;
          return $http.get(url, {
            params: {
              '>displayName': searchTerm,
              count: 5                      
            }
          }).then(function(response){
            var data = response.data.data;
            console.log('data:'+data);
            var requested = [];
            angular.forEach(data.requested, function(searchTerm, k, o) {
               requested.push(createDBOifNecessary(searchTerm));
            });
            $scope.item=[];
            $scope.options=[];
            $scope.options[name] = [];
            for (key in requested) {
              if (requested.hasOwnProperty(key)) {
                //This is the storing value
                //console.log(requested[key].cid);
                //this is the display value
                //console.log(requested[key].attributes.displayName[0]);
                $scope.options[name][key] = requested[key].attributes.displayName[0];
                $scope.item.push({
                  'theName':requested[key].attributes.displayName[0], 
                  'theVal':requested[key].cid
                }); 
              } 
            }   
            console.log('item:'+$scope.item);
            return $scope.item;

          });
        };

This last console.log returns the required data correctly!

For what I have been able to read the problem is related to the promise of the server request... but i am stuck!

Upvotes: 0

Views: 565

Answers (1)

Al Ex Tsm
Al Ex Tsm

Reputation: 2102

I am not sure what was failing because i was receiving the expected data.

I think as someone mentioned it could be related to the manipulation of the response, delaying it...

In stead I added an event trigger that updates the array the typeahead attribute reads from and it now works fine. As well the typeahead-wait-ms is required cause my server response is between 20 and 30ms so just to be safe I set it to 200ms.

working code:

view: displays the values of the array "item"(item.theName == x.theName)

  <input type="text" ng-model="selected"  typeahead="x.theName for x in item" ng-change="dynamicSearch($viewValue, field.displayName)" typeahead-wait-ms="1000"  class="form-control" typeahead-on-select='onSelect($item, field)'>

Controller functions:

On ng-change ->dynamicSearch() =>define what data request and call the request

$scope.dynamicSearch = function(searchTerm, name) {
  var allowed = {};
  var classString = "";
  allowed = datamodel.classes[$routeParams.class].attribute[name].allowed;
  for (key in allowed){
    classString = classString +  key + "|";
  }
  classString = classString.slice(0, -1);
  $scope.getDbRefDocs(searchTerm, name, classString);
};

On call of getDbRefDocs() => i define values for the array "item"

$scope.getDbRefDocs = function(searchTerm, name, classString) {
  var url = '/api/v2/docs/' + classString;
  $http.get(url, {
    params: {
      '>displayName': searchTerm,
      count: 5                      
    }
  }).then(function(response){
    var data = response.data.data;
    var requested = [];
    angular.forEach(data.requested, function(searchTerm, k, o) {
       requested.push(createDBOifNecessary(searchTerm));
    });
    $scope.item=[];
    for (key in requested) {
      if (requested.hasOwnProperty(key)) {
        $scope.item.push({
          'theName':requested[key].attributes.displayName[0], 
          'theVal':requested[key].cid
        }); 
      } 
    }   
  });
};

When item is selected from the available options of "item" => typeahead-on-select='onSelect($item, field)' => I store item.theVal:

    $scope.onSelect = function (item, field) {
      field.theValues[field.theValues.length] = item.theVal;
    };

Upvotes: 0

Related Questions