I am using AngularJS v1.6.6 and angular-ui-bootstrap Version: 2.5.0 to create an autocomplete field.
It all works correctly but I need a way to be sure that the user actually selects the option from the list of suggestions.
Here is my code:
HTML:
<div class='container-fluid typeahead-demo' ng-controller="TypeaheadCtrl">
<h4>How to prevent user from typing the whole word ignoring suggestions?</h4>
<div>Model:
<pre>{{selected | json}}</pre>
</div>
<form role="form" name="chooseStateForm" autocomplete="off" novalidate>
<div class="form-group required">
<div>
<label for="state" class="control-label col-sm-3">Choose a State:</label>
<input type="text"
class="form-control"
required
placeholder="Try typing the whole name of the state ignoring suggestion"
name="state"
ng-model="selected"
uib-typeahead="option as option.name for option in states | filter:{name: $viewValue}"
typeahead-min-length="1"
typeahead-no-results="noresults"
typeahead-show-hint="true"
>
</div>
<div ng-if="noresults">
<p>No match found!</p>
</div>
</div>
</form>
<br><br><br><br>
<div>
<button class="btn btn-primary" type="button" ng-click="$ctrl.ok()" ng-disabled="chooseStateForm.$invalid">OK</button>
<button class="btn btn-primary" type="button" ng-click="$ctrl.cancel()">Cancel</button>
</div>
JS:
angular.module('app', ['ui.bootstrap']);
angular.module('app').controller('TypeaheadCtrl', function($scope) {
$scope.selected = undefined;
$scope.states = [
{id: 1, name: 'Alabama'},
{id: 2, name: 'California'},
{id: 3, name: 'Delaware'},
{id: 4, name: 'Florida'},
{id: 5, name: 'Georgia'},
{id: 6, name: 'Hawaii'},
{id: 7, name: 'Idaho'},
{id: 8, name: 'Kansas'},
{id: 9, name: 'Louisiana'},
{id: 10, name: 'Maine'},
{id: 11, name: 'Nebraska'},
{id: 12, name: 'Ohio'},
{id: 13, name: 'Pennsylvania'},
{id: 14, name: 'Rhode Island'},
{id: 15, name: 'South Carolina'},
{id: 16, name: 'Tennessee'},
{id: 17, name: 'Utah'},
{id: 18, name: 'Vermont'},
{id: 19, name: 'Washington'}
];
});
See this jsfiddle and you will understand what I mean: http://jsfiddle.net/elenat82/yhpbdvva/20/
If the user wants, for example, to choose Ohio, since it is only 4 letters he could find it easier to just type "Ohio" than to choose the suggested option.
But doing this my model becomes a string whilst it is an object if he chooses from the suggestions list.
Yes I check the validity of the model in my controller but I want it to be done before the user submits the form, I would like to show an error message explaining to the user what he did wrong.
---------- EDIT ----------
I found another way to achieve the same result but using a directive and extending the $validators object.
Here is the link to the updated jsfiddle: http://jsfiddle.net/elenat82/fL5fw1up/2/
And here is the updated code:
HTML:
<div class='container-fluid typeahead-demo' ng-controller="TypeaheadCtrl">
<h4>How to prevent user from typing the whole word ignoring suggestions?</h4>
<div>Model:
<pre>{{selected | json}}</pre>
<div>Errors:
<pre>{{chooseStateForm.state.$error | json}}</pre>
</div>
<form role="form" name="chooseStateForm" autocomplete="off" novalidate>
<div class="form-group required">
<div>
<label for="state" class="control-label col-sm-3">Choose a State:</label>
<input type="text"
class="form-control"
required
placeholder="Try typing the whole name of the state ignoring suggestion"
name="state"
ng-model="selected"
uib-typeahead="option as option.name for option in states | filter:{name: $viewValue}"
typeahead-min-length="1"
typeahead-no-results="noresults"
typeahead-show-hint="true"
object
>
</div>
<div ng-if="noresults">
<p>No match found!</p>
</div>
</div>
</form>
<br><br><br><br>
<div>
<button class="btn btn-primary" type="button" ng-click="$ctrl.ok()" ng-disabled="chooseStateForm.$invalid">OK</button>
<button class="btn btn-primary" type="button" ng-click="$ctrl.cancel()">Cancel</button>
</div>
JS:
angular.module('app', ['ui.bootstrap']);
angular.module('app').controller('TypeaheadCtrl', function($scope) {
$scope.selected = undefined;
$scope.states = [
{id: 1, name: 'Alabama'},
{id: 2, name: 'California'},
{id: 3, name: 'Delaware'},
{id: 4, name: 'Florida'},
{id: 5, name: 'Georgia'},
{id: 6, name: 'Hawaii'},
{id: 7, name: 'Idaho'},
{id: 8, name: 'Kansas'},
{id: 9, name: 'Louisiana'},
{id: 10, name: 'Maine'},
{id: 11, name: 'Nebraska'},
{id: 12, name: 'Ohio'},
{id: 13, name: 'Pennsylvania'},
{id: 14, name: 'Rhode Island'},
{id: 15, name: 'South Carolina'},
{id: 16, name: 'Tennessee'},
{id: 17, name: 'Utah'},
{id: 18, name: 'Vermont'},
{id: 19, name: 'Washington'}
];
});
angular.module('app').directive('object', [function() {
return {
restrict: 'A',
scope: {},
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
ngModel.$validators.object = function(modelValue,viewValue){
if (angular.isObject(modelValue)) {
return true;
}
else {
return false;
}
};
}
};
}
]);
You can add method for this validation for example:
$scope.isSelected = function() {
return typeof $scope.selected == "object";
}
There is a property called typeahead-editable="false"
. If you set it to false, it will not allow the user to "not" choose something, the textbox will be set to empty.
Link: https://angular-ui.github.io/bootstrap/#!#typeahead
typeahead-editable $ (Default: true) - Should it restrict model values to the ones selected from the popup only?
You will need to traverse your array and check if the selected value (ngModel) exists on that array. You can define such a function and call it using ngChange
, that will run when you change your value
<input type="text"
class="form-control"
required
name="state"
ng-model="selected"
.....
ng-change="testIncluded(selected)">
And inside the controller, do something like this (using Array.prototype.find )
$scope.testIncluded = function(value) {
let isSelectedFromStates = $scope.states.find((state) => {
return state.name === value;
})
/// do something ...
}
If the name exists, isSelectedFromStates
will not be undefined
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.