-
Notifications
You must be signed in to change notification settings - Fork 1.8k
blur is not supported for tagging, tags just disappear #894
Comments
+1 |
+1 could something like this get committed to the main branch? My project is using bower and an automated build process so we have to avoid local fixes. |
+1 |
+1 |
Has anyone manage to extract this into a decorator? |
This is what I wrote in a controller. It also prevents duplicate tags from being added, which can break the UI unless you are using track by $index. I place this in a bootstrap-ui modal controller, but this could easily be placed in a directive's controller. If I get time today I will build a plnkr example with this in a directive. Let me know what you think // DOCUMENTATION: Initialize data model used by tagging UI
$scope.tagModel = {tags:[]};
// DOCUMENTATION: filter duplicates or the ui-select will break
$scope.filterTagDuplicates = function(){
if ($scope.blockFilterRecursion) {
$scope.blockFilterRecursion = false;
return;
}
var uniqueTags = [];
angular.forEach($scope.tagModel.tags,function(obj,i){
var dupe = false;
angular.forEach(uniqueTags, function(obj2,i2){
if (obj.name === obj2.name) dupe = true;
});
if (!dupe) uniqueTags.push(obj);
$scope.blockFilterRecursion = true;
$scope.tagModel.tags = uniqueTags;
});
};
// DOCUMENTATION: if user hits enter or tab it won't trigger the on blur function
// need to filter any duplicates if found
$scope.$watch('tagModel.tags', function(tags) {
if (!$scope.tagModel) return;
$scope.filterTagDuplicates();
});
// DOCUMENTATION: wait for modal to render, then register event listener
// listener adds tags on blur instead of just hitting enter
// this is kind of a hack until ui-select implements this.
// can't modify their source code locally
// due to the bower/grunt automated build
$timeout(function(){
$(".ui-select-search").on('blur', function(event){
var newTag = ($(".ui-select-search").val());
if ($(".ui-select-search").val() !== '') {
$scope.addTagIfUnique(newTag);
$scope.filterTagDuplicates();
$scope.$apply();
}
});
}, 1000);
// timeout probably doesn't need to be so long, I wait so the modal is rendered
// DOCUMENTATION: dont allow duplicate tags or ui-select will break
// ui-select uses ng-repeat which will break on duplicates if not tracking by index
$scope.addTagIfUnique = function(newTag) {
var dupe = false;
angular.forEach($scope.tagModel.tags, function(obj,i){
if (obj.name == newTag) {
dupe = true;
return false;
}
});
if (!dupe && $scope.tagModel.tags) $scope.tagModel.tags.push({"name":newTag,"type":"tag"});
if (!dupe && !$scope.tagModel.tags) $scope.tagModel.tags = [{"name":newTag,"type":"tag"}];
}; |
Ahh, much more involved than I imagined. Will take some time to digest this. |
The high level overview of what it does is this block $timeout(function(){
$(".ui-select-search").on('blur', function(event){
var newTag = ($(".ui-select-search").val());
if ($(".ui-select-search").val() !== '') {
$scope.addTagIfUnique(newTag);
$scope.filterTagDuplicates();
$scope.$apply();
}
});
}, 1000);
// timeout probably doesn't need to be so long, I wait so the modal is rendered |
|
I'm still digging for a simpler solution. I made a directive that would send the keycode of comma on the blur of a input element. But no dice. /**
* Send the comma key code on blur
*/
app.directive('commaOnBlur', function () {
'use strict';
var blurEvent = function (event) {
angular.element(event.currentTarget).trigger({
type: 'keydown',
keyCode: 188
});
event.stopPropagation();
};
return {
restrict: 'A',
link: function (scope, element) {
element.bind("blur", blurEvent);
}
};
}); |
I similarly was trying something that would send enter or comma on blur, but it wasn't reliable. That's why I landed on pushing the value of the input to my tag model on blur event, which has worked reliably. My solution really isn't that complex if you pare down the code that is removing and preventing duplicate tags. If you use track by $index and don't care about the dupes (which is another major shortcoming of ui-select's source code imo), then you're really only looking at something like this which is pretty simple, and you might not even need the timeout: // $scope.tagModel.tags is the array that the tagging interface uses for ng-model in this example
$scope.tagModel = {tags: []};
$timeout(function(){
$(".ui-select-search").on('blur', function(event){
var newTag = ($(".ui-select-search").val());
if ($(".ui-select-search").val() !== '') {
$scope.tagModel.tags.push(newTag);
$scope.$apply();
}
});
}, 1000); |
I'm still investigating the blur directive approach, though I am about to stop. I believe I have found the limitation in the source that limits the directive from succeeding. If the Lines 679 to 686 in bc3de20
|
Link to source, rather than dist. ui-select/src/uiSelectController.js Lines 442 to 449 in 5ba8986
|
There's a problem with the blur approach if the blur was caused by a choice in the dropdown. See my comment and solution here #1544 (comment) |
I made a local fix like this:
ctrl.searchInput.on('blur', function(e) {
var data = ctrl.searchInput.val();
if (data && data.length > 0 && ctrl.taggingTokens.isActivated) {
var items = data.split(ctrl.taggingTokens.tokens[0]); // split by first token only
if (items && items.length > 0) {
angular.forEach(items, function (item) {
ctrl.select(item, true);
});
e.preventDefault();
e.stopPropagation();
}
}
});
The text was updated successfully, but these errors were encountered: