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

Commit a85b1d6

Browse files
committed
implement tagging to single uiSelect
1 parent ac4a5df commit a85b1d6

File tree

2 files changed

+164
-164
lines changed

2 files changed

+164
-164
lines changed

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

src/uiSelectMultipleDirective.js

Lines changed: 0 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -264,170 +264,6 @@ uis.directive('uiSelectMultiple', ['uiSelectMinErr','$timeout', function(uiSelec
264264
return true;
265265
}
266266

267-
$select.searchInput.on('keyup', function(e) {
268-
269-
if ( ! KEY.isVerticalMovement(e.which) ) {
270-
scope.$evalAsync( function () {
271-
$select.activeIndex = $select.taggingLabel === false ? -1 : 0;
272-
});
273-
}
274-
// Push a "create new" item into array if there is a search string
275-
if ( $select.tagging.isActivated && $select.search.length > 0 ) {
276-
277-
// return early with these keys
278-
if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC || KEY.isVerticalMovement(e.which) ) {
279-
return;
280-
}
281-
// always reset the activeIndex to the first item when tagging
282-
$select.activeIndex = $select.taggingLabel === false ? -1 : 0;
283-
// taggingLabel === false bypasses all of this
284-
if ($select.taggingLabel === false) return;
285-
286-
var items = angular.copy( $select.items );
287-
var stashArr = angular.copy( $select.items );
288-
var newItem;
289-
var item;
290-
var hasTag = false;
291-
var dupeIndex = -1;
292-
var tagItems;
293-
var tagItem;
294-
295-
// case for object tagging via transform `$select.tagging.fct` function
296-
if ( $select.tagging.fct !== undefined) {
297-
tagItems = $select.$filter('filter')(items,{'isTag': true});
298-
if ( tagItems.length > 0 ) {
299-
tagItem = tagItems[0];
300-
}
301-
// remove the first element, if it has the `isTag` prop we generate a new one with each keyup, shaving the previous
302-
if ( items.length > 0 && tagItem ) {
303-
hasTag = true;
304-
items = items.slice(1,items.length);
305-
stashArr = stashArr.slice(1,stashArr.length);
306-
}
307-
newItem = $select.tagging.fct($select.search);
308-
// verify the new tag doesn't match the value of a possible selection choice or an already selected item.
309-
if (
310-
stashArr.some(function (origItem) {
311-
return angular.equals(origItem, newItem);
312-
}) ||
313-
$select.selected.some(function (origItem) {
314-
return angular.equals(origItem, newItem);
315-
})
316-
) {
317-
scope.$evalAsync(function () {
318-
$select.activeIndex = 0;
319-
$select.items = items;
320-
});
321-
return;
322-
}
323-
if (newItem) newItem.isTag = true;
324-
// handle newItem string and stripping dupes in tagging string context
325-
} else {
326-
// find any tagging items already in the $select.items array and store them
327-
tagItems = $select.$filter('filter')(items,function (item) {
328-
return item.match($select.taggingLabel);
329-
});
330-
if ( tagItems.length > 0 ) {
331-
tagItem = tagItems[0];
332-
}
333-
item = items[0];
334-
// remove existing tag item if found (should only ever be one tag item)
335-
if ( item !== undefined && items.length > 0 && tagItem ) {
336-
hasTag = true;
337-
items = items.slice(1,items.length);
338-
stashArr = stashArr.slice(1,stashArr.length);
339-
}
340-
newItem = $select.search+' '+$select.taggingLabel;
341-
if ( _findApproxDupe($select.selected, $select.search) > -1 ) {
342-
return;
343-
}
344-
// verify the the tag doesn't match the value of an existing item from
345-
// the searched data set or the items already selected
346-
if ( _findCaseInsensitiveDupe(stashArr.concat($select.selected)) ) {
347-
// if there is a tag from prev iteration, strip it / queue the change
348-
// and return early
349-
if ( hasTag ) {
350-
items = stashArr;
351-
scope.$evalAsync( function () {
352-
$select.activeIndex = 0;
353-
$select.items = items;
354-
});
355-
}
356-
return;
357-
}
358-
if ( _findCaseInsensitiveDupe(stashArr) ) {
359-
// if there is a tag from prev iteration, strip it
360-
if ( hasTag ) {
361-
$select.items = stashArr.slice(1,stashArr.length);
362-
}
363-
return;
364-
}
365-
}
366-
if ( hasTag ) dupeIndex = _findApproxDupe($select.selected, newItem);
367-
// dupe found, shave the first item
368-
if ( dupeIndex > -1 ) {
369-
items = items.slice(dupeIndex+1,items.length-1);
370-
} else {
371-
items = [];
372-
if (newItem) items.push(newItem);
373-
items = items.concat(stashArr);
374-
}
375-
scope.$evalAsync( function () {
376-
$select.activeIndex = 0;
377-
$select.items = items;
378-
379-
if ($select.isGrouped) {
380-
// update item references in groups, so that indexOf will work after angular.copy
381-
var itemsWithoutTag = newItem ? items.slice(1) : items;
382-
$select.setItemsFn(itemsWithoutTag);
383-
if (newItem) {
384-
// add tag item as a new group
385-
$select.items.unshift(newItem);
386-
$select.groups.unshift({name: '', items: [newItem], tagging: true});
387-
}
388-
}
389-
});
390-
}
391-
});
392-
function _findCaseInsensitiveDupe(arr) {
393-
if ( arr === undefined || $select.search === undefined ) {
394-
return false;
395-
}
396-
var hasDupe = arr.filter( function (origItem) {
397-
if ( $select.search.toUpperCase() === undefined || origItem === undefined ) {
398-
return false;
399-
}
400-
return origItem.toUpperCase() === $select.search.toUpperCase();
401-
}).length > 0;
402-
403-
return hasDupe;
404-
}
405-
function _findApproxDupe(haystack, needle) {
406-
var dupeIndex = -1;
407-
if(angular.isArray(haystack)) {
408-
var tempArr = angular.copy(haystack);
409-
for (var i = 0; i <tempArr.length; i++) {
410-
// handle the simple string version of tagging
411-
if ( $select.tagging.fct === undefined ) {
412-
// search the array for the match
413-
if ( tempArr[i]+' '+$select.taggingLabel === needle ) {
414-
dupeIndex = i;
415-
}
416-
// handle the object tagging implementation
417-
} else {
418-
var mockObj = tempArr[i];
419-
if (angular.isObject(mockObj)) {
420-
mockObj.isTag = true;
421-
}
422-
if ( angular.equals(mockObj, needle) ) {
423-
dupeIndex = i;
424-
}
425-
}
426-
}
427-
}
428-
return dupeIndex;
429-
}
430-
431267
$select.searchInput.on('blur', function() {
432268
$timeout(function() {
433269
$selectMultiple.activeMatchIndex = -1;

0 commit comments

Comments
 (0)