jquery Select2 prevent selecting in ajax response

I want to prevent from adding a category to the Select2 element if it fails creating the row first in my db. The action is not prevented when i call ev.preventDefault(); Nothing happens.. what is wrong?

    $('#sel2').select2({
            placeholder: 'Enter categories',
            minimumInputLength: 3,
            multiple: true,
            ajax: {
                url: 'async/get_categories.php',
                dataType: 'json',
                quietMillis: 250,
                data: function (term, page) {
                    return {
                        q: term,
                    };
                },
                results: function (data, page) {
                    return {
                        results: data.items 
                    };
                },
                cache: true
            },
            formatResult: format,
            formatSelection: format
        }).on('select2-selecting', function(e) {
            console.log(e);
            if (e.val == 4) {
                // if category id equals 4
                // do not add this category to select 2
                // e.preventDefault();
                // the above works just fine and its just for testing
            }

            // Is something wrong here?
            var ev = e;

            $.ajax({
                type: 'POST',
                url: 'async/create_profile_category.php',
                data: {
                    profile_id: '1', 
                    category_id: ev.val
                },
                success: function(response) {
                    console.log(response);
                    if (response.error === false) {
                        // category assigned successfully
                    } else {
                        // failed to assign category
                        // so i want now to prevent from adding to select2
                        console.log('should not add this category');
                        ev.preventDefault();
                        // the above is not working
                    }
                },
                error: function() {
                    alert('Failed to assign category!');
                }
            });
        });

Answer

The AJAX request is made asynchronusly, so by the time it has finished the element has already been added. Even though you are calling ev.preventDefault(), it is too late for it to make a difference. So this leaves you with two options:

  1. Make the request synchronusly, which will allow preventDefault to make the difference.
  2. Make the request asynchronusly, and manually remove the element if it fails.

Both options have their pros and cons, and it’s up to you to decide which option you go with.


  1. Making the request synchronusly

Pros

  • The value will never be added if the request fails.
  • Works well in cases where the element cannot be added quite often.

Cons

  • Blocks the UI – So the user is potentially left with an unresponsive page while the request is made.

  1. Making the request asynchronusly

Pros

  • Does not block the UI.
  • Works well in cases where elements typically can be added.

Cons

  • The value will always show up for the user, even if it fails later.
  • You must manually unset the new option.

What’s important to consider here is the user experience of both options. When making synchronus requests, it’s not uncommon for the browser to stop relaying events – which gives the illusion that the UI has locked up and the page has gone unresponsive. This has the benefit of ensuring that the value never shows up if it isn’t allowed. But if users typically can add the elements, it also has the downside of complicating the most common use case.

If users can usually add elements, then it is a better experience to add the element while the request is being made, and then notifying the user later (while removing the element) if there was an issue. This is very common is web applications, and you can see it being used in many places, such as the Twitter and Facebook like buttons (where requests usually work), as well as places on Stack Overflow.

Leave a Reply

Your email address will not be published. Required fields are marked *