Skip to content

Commit 6652d5e

Browse files
author
Patrice de Saint Steban
committed
Add required html5 option
if there are the attriute required, the form can't be submitted
1 parent c6cf47b commit 6652d5e

File tree

7 files changed

+165
-3
lines changed

7 files changed

+165
-3
lines changed

examples/demo-required-html5.html

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<!DOCTYPE html>
2+
<html lang="en" ng-app="demo">
3+
<head>
4+
<meta charset="utf-8">
5+
<title>AngularJS ui-select</title>
6+
7+
<!--
8+
IE8 support, see AngularJS Internet Explorer Compatibility http://docs.angularjs.org/guide/ie
9+
For Firefox 3.6, you will also need to include jQuery and ECMAScript 5 shim
10+
-->
11+
<!--[if lt IE 9]>
12+
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.js"></script>
13+
<script src="http://cdnjs.cloudflare.com/ajax/libs/es5-shim/2.2.0/es5-shim.js"></script>
14+
<script>
15+
document.createElement('ui-select');
16+
document.createElement('ui-select-match');
17+
document.createElement('ui-select-choices');
18+
</script>
19+
<![endif]-->
20+
21+
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular.js"></script>
22+
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular-sanitize.js"></script>
23+
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.css">
24+
25+
<!-- ui-select files -->
26+
<script src="../dist/select.js"></script>
27+
<link rel="stylesheet" href="../dist/select.css">
28+
29+
<script src="demo.js"></script>
30+
31+
<!-- Select2 theme -->
32+
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/select2/3.4.5/select2.css">
33+
34+
<!--
35+
Selectize theme
36+
Less versions are available at https://github.com/brianreavis/selectize.js/tree/master/dist/less
37+
-->
38+
<!--<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.8.5/css/selectize.default.css">-->
39+
<!-- <link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.8.5/css/selectize.bootstrap2.css"> -->
40+
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.8.5/css/selectize.bootstrap3.css">
41+
42+
<style>
43+
body {
44+
padding: 15px;
45+
}
46+
47+
.select2 > .select2-choice.ui-select-match {
48+
/* Because of the inclusion of Bootstrap */
49+
height: 29px;
50+
}
51+
52+
.selectize-control > .selectize-dropdown {
53+
top: 36px;
54+
}
55+
</style>
56+
</head>
57+
58+
<body ng-controller="DemoCtrl">
59+
<script src="demo.js"></script>
60+
61+
<button class="btn btn-default btn-xs" ng-click="enable()">Enable ui-select</button>
62+
<button class="btn btn-default btn-xs" ng-click="disable()">Disable ui-select</button>
63+
<button class="btn btn-default btn-xs" ng-click="enableRequired()" ng-init="required = true" ng-disabled="required">Enable Required</button>
64+
<button class="btn btn-default btn-xs" ng-click="disableRequired()" ng-disabled="!required">Disable Required</button>
65+
<button class="btn btn-default btn-xs" ng-click="clear();">Clear ng-model</button>
66+
67+
<h3>Select with required html5 validation</h3>
68+
<p>Submited: {{person.submitted|json}}</p>
69+
<form ng-submit="person.submitted = [person.selected,person.selected2,person.selected3]">
70+
<div class="row form-group">
71+
<label class="col-sm-3 control-label">Boostrap</label>
72+
<div class="col-sm-6">
73+
74+
<ui-select ng-model="person.selected" theme="bootstrap" ng-disabled="disabled" ng-required="required" title="Choose a person" on-select="clearSubmited($item)">
75+
<ui-select-match placeholder="Select a person in the list or search his name/age..." allow-clear="true">{{$select.selected.name}}</ui-select-match>
76+
<ui-select-choices repeat="person.email as person in people | propsFilter: {name: $select.search, age: $select.search}">
77+
<div ng-bind-html="person.name | highlight: $select.search"></div>
78+
<small>
79+
email: {{person.email}}
80+
age: <span ng-bind-html="''+person.age | highlight: $select.search"></span>
81+
</small>
82+
</ui-select-choices>
83+
</ui-select>
84+
85+
</div>
86+
</div>
87+
<br/>
88+
<div class="row">
89+
<label class="col-sm-3 control-label">Select2</label>
90+
<div class="col-sm-6">
91+
<ui-select ng-model="person.selected2" theme="select2" ng-disabled="disabled" style="width: 300px;" ng-required="required" title="Choose a person" on-select="clearSubmited($item)">
92+
<ui-select-match placeholder="Select a person in the list or search his name/age..." allow-clear="true">{{$select.selected.name}}</ui-select-match>
93+
<ui-select-choices repeat="person.email as person in people | propsFilter: {name: $select.search, age: $select.search}">
94+
<div ng-bind-html="person.name | highlight: $select.search"></div>
95+
<small>
96+
email: {{person.email}}
97+
age: <span ng-bind-html="''+person.age | highlight: $select.search"></span>
98+
</small>
99+
</ui-select-choices>
100+
</ui-select>
101+
</div>
102+
</div>
103+
<br/>
104+
<div class="row">
105+
<label class="col-sm-3 control-label">Selectize</label>
106+
<div class="col-sm-6">
107+
<ui-select ng-model="person.selected3" theme="selectize" ng-disabled="disabled" style="width: 300px;" ng-required="required" title="Choose a person" on-select="clearSubmited($item)">
108+
<ui-select-match placeholder="Select a person in the list or search his name/age..." allow-clear="true">{{$select.selected.name}}</ui-select-match>
109+
<ui-select-choices repeat="person.email as person in people | propsFilter: {name: $select.search, age: $select.search}">
110+
<div ng-bind-html="person.name | highlight: $select.search"></div>
111+
<small>
112+
email: {{person.email}}
113+
age: <span ng-bind-html="''+person.age | highlight: $select.search"></span>
114+
</small>
115+
</ui-select-choices>
116+
</ui-select>
117+
</div>
118+
</div>
119+
120+
<button class="btn btn-default" type="submit">Send</button>
121+
</form>
122+
</body>
123+
124+
</html>

examples/demo.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ app.controller('DemoCtrl', function($scope, $http, $timeout, $interval) {
5656
$scope.disabled = true;
5757
};
5858

59+
$scope.enableRequired = function() {
60+
$scope.required = true;
61+
};
62+
63+
$scope.disableRequired = function() {
64+
$scope.required = false;
65+
};
66+
5967
$scope.enableSearch = function() {
6068
$scope.searchEnabled = true;
6169
};
@@ -66,6 +74,9 @@ app.controller('DemoCtrl', function($scope, $http, $timeout, $interval) {
6674

6775
$scope.clear = function() {
6876
$scope.person.selected = undefined;
77+
$scope.person.selected2 = undefined;
78+
$scope.person.selected3 = undefined;
79+
$scope.person.submitted = undefined;
6980
$scope.address.selected = undefined;
7081
$scope.country.selected = undefined;
7182
};
@@ -208,7 +219,11 @@ app.controller('DemoCtrl', function($scope, $http, $timeout, $interval) {
208219
delete item.isTag;
209220
$scope.people.push(item);
210221
}
211-
}
222+
};
223+
224+
$scope.clearSubmited = function($item) {
225+
if (!$item) { $scope.person.submitted = undefined }
226+
};
212227

213228
$scope.country = {};
214229
$scope.countries = [ // Taken from https://gist.github.com/unceus/6501985

src/bootstrap/match.tpl.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
ng-disabled="$select.disabled"
66
ng-click="$select.activate()"
77
style="outline: 0;">
8-
<span ng-show="$select.isEmpty()" class="ui-select-placeholder text-muted">{{$select.placeholder}}</span>
8+
<input ng-show="$select.isEmpty()" ng-required="$select.required" aria-label="{{ $select.baseTitle }}" class="ui-select-placeholder text-muted" placeholder="{{$select.placeholder}}" ng-value="$select.isEmpty()?'':'notempty'" style="border:none;width:100%;background-color: transparent;outline: none;">
99
<span ng-hide="$select.isEmpty()" class="ui-select-match-text pull-left" ng-class="{'ui-select-allow-clear': $select.allowClear && !$select.isEmpty()}" ng-transclude=""></span>
1010
<i class="caret pull-right" ng-click="$select.toggle($event)"></i>
1111
<a ng-show="$select.allowClear && !$select.isEmpty()" aria-label="{{ $select.baseTitle }} clear" style="margin-right: 10px"

src/select2/match.tpl.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<a class="select2-choice ui-select-match"
77
ng-class="{'select2-default': $select.isEmpty()}"
88
ng-click="$select.toggle($event)" aria-label="{{ $select.baseTitle }} select">
9-
<span ng-show="$select.isEmpty()" class="select2-chosen">{{$select.placeholder}}</span>
9+
<input ng-show="$select.isEmpty()" aria-label="{{ $select.baseTitle }}" ng-required="$select.required" class="select2-chosen" placeholder="{{$select.placeholder}}" ng-value="$select.isEmpty()?'':'notempty'" style="border:none;width:100%;background-color: transparent;outline: none;">
1010
<span ng-hide="$select.isEmpty()" class="select2-chosen" ng-transclude></span>
1111
<abbr ng-if="$select.allowClear && !$select.isEmpty()" class="select2-search-choice-close" ng-click="$select.clear($event)"></abbr>
1212
<span class="select2-arrow ui-select-toggle"><b></b></span>

src/selectize/select.tpl.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
ng-model="$select.search"
1111
ng-hide="!$select.searchEnabled || ($select.selected && !$select.open)"
1212
ng-disabled="$select.disabled"
13+
ng-required="$select.isEmpty() && $select.required"
1314
aria-label="{{ $select.baseTitle }}">
1415
</div>
1516
<div class="ui-select-choices"></div>

src/uiSelectDirective.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ uis.directive('uiSelect',
8787
$select.disabled = attrs.disabled !== undefined ? attrs.disabled : false;
8888
});
8989

90+
attrs.$observe('required', function() {
91+
// No need to use $eval() (thanks to ng-disabled) since we already get a boolean instead of a string
92+
$select.required = attrs.required !== undefined ? attrs.required : false;
93+
});
94+
9095
attrs.$observe('resetSearchInput', function() {
9196
// $eval() is needed otherwise we get a string instead of a boolean
9297
var resetSearchInput = scope.$eval(attrs.resetSearchInput);

test/select.spec.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,12 @@ describe('ui-select tests', function() {
173173
e.keyCode = keyCode;
174174
element.trigger(e);
175175
}
176+
function triggerKeyup(element, keyCode) {
177+
var e = jQuery.Event("keyup");
178+
e.which = keyCode;
179+
e.keyCode = keyCode;
180+
element.trigger(e);
181+
}
176182
function triggerPaste(element, text, isClipboardEvent) {
177183
var e = jQuery.Event("paste");
178184
if (isClipboardEvent) {
@@ -511,6 +517,17 @@ describe('ui-select tests', function() {
511517
expect(isDropdownOpened(el3)).toEqual(true);
512518
});
513519

520+
it('should be required if the attribute says so', function() {
521+
var el1 = createUiSelect({required: true});
522+
expect(el1.scope().$select.required).toEqual(true);
523+
524+
var el2 = createUiSelect({required: false});
525+
expect(el2.scope().$select.required).toEqual(false);
526+
527+
var el3 = createUiSelect();
528+
expect(el3.scope().$select.required).toBeFalsy();
529+
});
530+
514531
it('should allow decline tags when tagging function returns null', function() {
515532
scope.taggingFunc = function (name) {
516533
return null;

0 commit comments

Comments
 (0)