Skip to content
This repository was archived by the owner on Oct 2, 2019. It is now read-only.

Commit 2e1f5bf

Browse files
committed
implement tagging label for all type of uiSelect
1 parent c9232e8 commit 2e1f5bf

File tree

4 files changed

+194
-165
lines changed

4 files changed

+194
-165
lines changed

examples/demo-tagging.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,16 @@ <h3>Tagging without multiple, with simple strings</h3>
140140
<p>Selected: {{singleDemo.color}}</p>
141141

142142

143+
<h3>Tagging without multiple with label and complex objects</h3>
144+
<ui-select tagging="convertToPerson" on-select="onSelect($item, $model)" ng-model="person.selected" ng-disabled="disabled" title="Choose a person" style="width: 800px;">
145+
<ui-select-match placeholder="Selecione um cliente">{{$select.selected.name}}</ui-select-match>
146+
<ui-select-choices repeat="person in people | propsFilter: {name: $select.search} track by person.name" >
147+
<div ng-if="person.isTag" ng-bind-html="person.name +' <small>(new)</small>'"></div>
148+
<div ng-if="!person.isTag" ng-bind-html="person.name | highlight: $select.search"></div>
149+
</ui-select-choices>
150+
</ui-select>
151+
<p>Selected: {{person.selected}}</p>
152+
143153
<div style="height:500px"></div>
144154

145155
</body>

examples/demo.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ app.filter('propsFilter', function() {
1414

1515
if (angular.isArray(items)) {
1616
var keys = Object.keys(props);
17-
17+
1818
items.forEach(function(item) {
1919
var itemMatches = false;
2020

@@ -130,6 +130,7 @@ app.controller('DemoCtrl', function($scope, $http, $timeout, $interval) {
130130
return item;
131131
};
132132

133+
133134
$scope.peopleObj = {
134135
'1' : { name: 'Adam', email: '[email protected]', age: 12, country: 'United States' },
135136
'2' : { name: 'Amalie', email: '[email protected]', age: 12, country: 'Argentina' },
@@ -143,6 +144,24 @@ app.controller('DemoCtrl', function($scope, $http, $timeout, $interval) {
143144
'10' : { name: 'Nicolás', email: '[email protected]', age: 43, country: 'Colombia' }
144145
};
145146

147+
$scope.convertToPerson = function (newPersonName) {
148+
var person = {
149+
name: newPersonName
150+
};
151+
152+
return person;
153+
};
154+
155+
$scope.onSelect = function($item, $model){
156+
if(!$item.isTag){
157+
return false;
158+
}
159+
var item = angular.copy($item);
160+
delete item.isTag;
161+
162+
$scope.people.push(item);
163+
};
164+
146165
$scope.person = {};
147166

148167
$scope.person.selectedValue = $scope.peopleObj[3];

src/uiSelectController.js

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,170 @@ uis.controller('uiSelectCtrl',
561561

562562
});
563563

564+
ctrl.searchInput.on('keyup', function(e) {
565+
566+
if ( ! KEY.isVerticalMovement(e.which) ) {
567+
$scope.$evalAsync( function () {
568+
ctrl.activeIndex = ctrl.taggingLabel === false ? -1 : 0;
569+
});
570+
}
571+
// Push a "create new" item into array if there is a search string
572+
if ( ctrl.tagging.isActivated && ctrl.search.length > 0 ) {
573+
574+
// return early with these keys
575+
if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC || KEY.isVerticalMovement(e.which) ) {
576+
return;
577+
}
578+
// always reset the activeIndex to the first item when tagging
579+
ctrl.activeIndex = ctrl.taggingLabel === false ? -1 : 0;
580+
// taggingLabel === false bypasses all of this
581+
if (ctrl.taggingLabel === false) return;
582+
583+
var items = angular.copy( ctrl.items );
584+
var stashArr = angular.copy( ctrl.items );
585+
var newItem;
586+
var item;
587+
var hasTag = false;
588+
var dupeIndex = -1;
589+
var tagItems;
590+
var tagItem;
591+
592+
// case for object tagging via transform `ctrl.tagging.fct` function
593+
if ( ctrl.tagging.fct !== undefined) {
594+
tagItems = ctrl.$filter('filter')(items,{'isTag': true});
595+
if ( tagItems.length > 0 ) {
596+
tagItem = tagItems[0];
597+
}
598+
// remove the first element, if it has the `isTag` prop we generate a new one with each keyup, shaving the previous
599+
if ( items.length > 0 && tagItem ) {
600+
hasTag = true;
601+
items = items.slice(1,items.length);
602+
stashArr = stashArr.slice(1,stashArr.length);
603+
}
604+
newItem = ctrl.tagging.fct(ctrl.search);
605+
// verify the new tag doesn't match the value of a possible selection choice or an already selected item.
606+
if (
607+
stashArr.some(function (origItem) {
608+
return angular.equals(origItem, newItem);
609+
}) ||
610+
(ctrl.selected && ctrl.selected.some(function (origItem) {
611+
return angular.equals(origItem, newItem);
612+
}))
613+
) {
614+
$scope.$evalAsync(function () {
615+
ctrl.activeIndex = 0;
616+
ctrl.items = items;
617+
});
618+
return;
619+
}
620+
if (newItem) newItem.isTag = true;
621+
// handle newItem string and stripping dupes in tagging string context
622+
} else {
623+
// find any tagging items already in the ctrl.items array and store them
624+
tagItems = ctrl.$filter('filter')(items,function (item) {
625+
return item.match(ctrl.taggingLabel);
626+
});
627+
if ( tagItems.length > 0 ) {
628+
tagItem = tagItems[0];
629+
}
630+
item = items[0];
631+
// remove existing tag item if found (should only ever be one tag item)
632+
if ( item !== undefined && items.length > 0 && tagItem ) {
633+
hasTag = true;
634+
items = items.slice(1,items.length);
635+
stashArr = stashArr.slice(1,stashArr.length);
636+
}
637+
newItem = ctrl.search+' '+ctrl.taggingLabel;
638+
if ( _findApproxDupe(ctrl.selected, ctrl.search) > -1 ) {
639+
return;
640+
}
641+
// verify the the tag doesn't match the value of an existing item from
642+
// the searched data set or the items already selected
643+
if ( _findCaseInsensitiveDupe(stashArr.concat(ctrl.selected)) ) {
644+
// if there is a tag from prev iteration, strip it / queue the change
645+
// and return early
646+
if ( hasTag ) {
647+
items = stashArr;
648+
$scope.$evalAsync( function () {
649+
ctrl.activeIndex = 0;
650+
ctrl.items = items;
651+
});
652+
}
653+
return;
654+
}
655+
if ( _findCaseInsensitiveDupe(stashArr) ) {
656+
// if there is a tag from prev iteration, strip it
657+
if ( hasTag ) {
658+
ctrl.items = stashArr.slice(1,stashArr.length);
659+
}
660+
return;
661+
}
662+
}
663+
if ( hasTag ) dupeIndex = _findApproxDupe(ctrl.selected, newItem);
664+
// dupe found, shave the first item
665+
if ( dupeIndex > -1 ) {
666+
items = items.slice(dupeIndex+1,items.length-1);
667+
} else {
668+
items = [];
669+
if (newItem) items.push(newItem);
670+
items = items.concat(stashArr);
671+
}
672+
$scope.$evalAsync( function () {
673+
ctrl.activeIndex = 0;
674+
ctrl.items = items;
675+
676+
if (ctrl.isGrouped) {
677+
// update item references in groups, so that indexOf will work after angular.copy
678+
var itemsWithoutTag = newItem ? items.slice(1) : items;
679+
ctrl.setItemsFn(itemsWithoutTag);
680+
if (newItem) {
681+
// add tag item as a new group
682+
ctrl.items.unshift(newItem);
683+
ctrl.groups.unshift({name: '', items: [newItem], tagging: true});
684+
}
685+
}
686+
});
687+
}
688+
});
689+
function _findCaseInsensitiveDupe(arr) {
690+
if ( arr === undefined || ctrl.search === undefined ) {
691+
return false;
692+
}
693+
var hasDupe = arr.filter( function (origItem) {
694+
if ( ctrl.search.toUpperCase() === undefined || origItem === undefined ) {
695+
return false;
696+
}
697+
return origItem.toUpperCase() === ctrl.search.toUpperCase();
698+
}).length > 0;
699+
700+
return hasDupe;
701+
}
702+
function _findApproxDupe(haystack, needle) {
703+
var dupeIndex = -1;
704+
if(angular.isArray(haystack)) {
705+
var tempArr = angular.copy(haystack);
706+
for (var i = 0; i <tempArr.length; i++) {
707+
// handle the simple string version of tagging
708+
if ( ctrl.tagging.fct === undefined ) {
709+
// search the array for the match
710+
if ( tempArr[i]+' '+ctrl.taggingLabel === needle ) {
711+
dupeIndex = i;
712+
}
713+
// handle the object tagging implementation
714+
} else {
715+
var mockObj = tempArr[i];
716+
if (angular.isObject(mockObj)) {
717+
mockObj.isTag = true;
718+
}
719+
if ( angular.equals(mockObj, needle) ) {
720+
dupeIndex = i;
721+
}
722+
}
723+
}
724+
}
725+
return dupeIndex;
726+
}
727+
564728
ctrl.searchInput.on('paste', function (e) {
565729
var data;
566730

0 commit comments

Comments
 (0)