如何防止用户表单忽略 angularjs angular-ui-bootstrap uib-typeahead 中的建议
How to prevent user form ignoring suggestion in angularjs angular-ui-bootstrap uib-typeahead
我正在使用 AngularJS v1.6.6 和 angular-ui-bootstrap 版本:2.5.0 创建一个自动完成字段。
一切正常,但我需要一种方法来确保用户确实从建议列表中选择了选项。
这是我的代码:
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'}
];
});
看到这个jsfiddle你就会明白我的意思了:http://jsfiddle.net/elenat82/yhpbdvva/20/
例如,如果用户想要选择俄亥俄州,因为它只有 4 个字母,他会发现直接键入 "Ohio" 比选择建议的选项更容易。
但是这样做我的模型变成了一个字符串,而如果他从建议列表中选择它是一个对象。
是的,我在我的控制器中检查模型的有效性,但我希望它在用户提交表单之前完成,我想显示一条错误消息,向用户解释他做错了什么。
------------编辑---------
我找到了另一种实现相同结果的方法,但使用指令并扩展了 $validators 对象。
这是更新后的 jsfiddle 的 link:http://jsfiddle.net/elenat82/fL5fw1up/2/
这是更新后的代码:
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;
}
};
}
};
}
]);
您可以为此验证添加方法,例如:
$scope.isSelected = function() {
return typeof $scope.selected == "object";
}
您将需要遍历数组并检查所选值 (ngModel) 是否存在于该数组中。您可以定义这样一个函数并使用 ngChange
调用它,当您更改值
时,它将 运行
<input type="text"
class="form-control"
required
name="state"
ng-model="selected"
.....
ng-change="testIncluded(selected)">
在控制器内部,做这样的事情(使用Array.prototype.find)
$scope.testIncluded = function(value) {
let isSelectedFromStates = $scope.states.find((state) => {
return state.name === value;
})
/// do something ...
}
如果名字存在,isSelectedFromStates
不会是undefined
有个叫typeahead-editable="false"
的属性。
如果将其设置为 false,将不允许用户 "not" 选择内容,文本框将设置为空。
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?
我正在使用 AngularJS v1.6.6 和 angular-ui-bootstrap 版本:2.5.0 创建一个自动完成字段。
一切正常,但我需要一种方法来确保用户确实从建议列表中选择了选项。
这是我的代码:
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'}
];
});
看到这个jsfiddle你就会明白我的意思了:http://jsfiddle.net/elenat82/yhpbdvva/20/
例如,如果用户想要选择俄亥俄州,因为它只有 4 个字母,他会发现直接键入 "Ohio" 比选择建议的选项更容易。
但是这样做我的模型变成了一个字符串,而如果他从建议列表中选择它是一个对象。
是的,我在我的控制器中检查模型的有效性,但我希望它在用户提交表单之前完成,我想显示一条错误消息,向用户解释他做错了什么。
------------编辑---------
我找到了另一种实现相同结果的方法,但使用指令并扩展了 $validators 对象。
这是更新后的 jsfiddle 的 link:http://jsfiddle.net/elenat82/fL5fw1up/2/
这是更新后的代码:
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;
}
};
}
};
}
]);
您可以为此验证添加方法,例如:
$scope.isSelected = function() {
return typeof $scope.selected == "object";
}
您将需要遍历数组并检查所选值 (ngModel) 是否存在于该数组中。您可以定义这样一个函数并使用 ngChange
调用它,当您更改值
<input type="text"
class="form-control"
required
name="state"
ng-model="selected"
.....
ng-change="testIncluded(selected)">
在控制器内部,做这样的事情(使用Array.prototype.find)
$scope.testIncluded = function(value) {
let isSelectedFromStates = $scope.states.find((state) => {
return state.name === value;
})
/// do something ...
}
如果名字存在,isSelectedFromStates
不会是undefined
有个叫typeahead-editable="false"
的属性。
如果将其设置为 false,将不允许用户 "not" 选择内容,文本框将设置为空。
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?