Reputation: 2102
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:
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
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