Registering blur / focusout events on a select2 multiselect


#1

I’m using the latest version of select2 (loaded remotely, via cdn.jsdelivr.net).

Here’s what I’m trying to do. I have a table with various data, and one of the columns has tags (spans with different backgrounds and text). I want to be able to let the user double click the table cell with the tags, which then changes the contents to a select2 multiselect element, populated with options from an AJAX call. And that’s fine and dandy, and works as I’d hoped (all the code is at the very bottom of this post).

The user then changes the tags / selected options - selects new ones, drops the old ones, etc. After they’re done, on blur / focusout (I know they’re different events, just saying I’ve tried both), AJAX triggers, and whatever the user has chosen in multiselect is inserted into the database. This is where the problem happens. Blur / focusout events are triggered while the user is choosing the tags - clicking on them in the dropdown, navigating with the arrows, typing in order to filter down the tags.

From what I’ve seen after Googling a bit, this seems to have been an issue a while back, but it’s not supposed to be happening anymore.

EDIT I’ve also tried going with select2-cointainer–focus and select2-search__field inside the “focusout” bit, and I’ve had these issues as well.

This is my code.

// populate the cell with the options from the AJAX call
	$('body').on('dblclick','.clickTags',function(){
		var me = $(this);
		var polId = me.data('id');
		$.ajax({
			url: 'return-tags.php',
			type: 'POST',
			global: false,
			async: false,
			dataType: 'html',
			data: {'polId':polId},
			success: function(data) {
				if(data) {
					me.html('<select name="varTags[]" id="varTags" class="form-control w-100 select2 changeTags" multiple data-id="'+polId+'">'+data+'</select>');
					$('body #varTags').select2();
				}
			}
		});
	});

// upon leaving the select2 multiselect element, make another AJAX call, and replace the contents with whatever comes from the call
	$('body').on("focusout",".changeTags",function(e){
		var originalElem = $(this).closest('td');
		var polId = $(this).data('id');
		var newTags = $(this).val();
		$.ajax({
			url:'change-tags.php',
			type:'post',
			data:{'polId':polId,'newTags':newTags},
			success:function(data){
				if(data){
					originalElem.html(data);
				}
			}
		});
	});

#2

So, I’ve managed to solve it. I’m not quite happy with the way I’ve made it work, and there are more than a few reasons why it shouldn’t be done like this, but it works.

// populate the cell with the options from the AJAX call
	$('body').on('dblclick','.clickTags',function(){
		// check if there's already a quick-change multiselect element open, and if there is, force the focusout()
		if($('#changeTags').length) {
			$('body .select2-search__field').focusout();
		}
		var me = $(this);
		var polId = me.data('id');
		$.ajax({
			url: 'return-tags.php',
			type: 'POST',
			global: false,
			async: false,
			dataType: 'html',
			data: {'polId':polId},
			success: function(data) {
				if(data) {
					me.html('<select name="varTags[]" id="varTags" class="form-control w-100 select2 changeTags" multiple data-id="'+polId+'">'+data+'</select>');
					$('body #varTags').select2();
					// force the focus on the input / search field within the multiselect
					$('.select2-search__field').focus();
				}
			}
		});
	});

// upon leaving the select2 multiselect element, make another AJAX call, and replace the contents with whatever comes from the call
	$('body').on('focusout','.select2-search__field',function(e){

	// this isn't the best way of doing it, and it's quite hacky, but it works
		setTimeout(function(){
			var searchTest = $('.select2-container--focus').length;
			var searchTestOpen = $('.select2-container--open').length;

			// test if anything's in focus - the select2 multiselect dropdown, or the input search field itself - if they're not open, do the AJAX call with whatever was inside
			if(!searchTest && !searchTestOpen) {
				var originalElem = $(this).closest('td');
				var polId = $(this).data('id');
				var newTags = $(this).val();
				$.ajax({
					url:'change-tags.php',
					type:'post',
					data:{'polId':polId,'newTags':newTags},
					success:function(data){
						if(data){
							originalElem.html(data);
						}
					}
				});
			}
		},200);
	});