jquery Select2 prevent selecting in ajax response
Asked Answered
G

4

13

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!');
                }
            });
        });
Greff answered 2/11, 2014 at 22:18 Comment(0)
S
11

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.

Schutt answered 3/11, 2014 at 1:53 Comment(0)
P
10

There is a way to get around this with version4 of the select2 library.

on select2:selecting we cancel the preTrigger event. Which will stop the select2:select event. We do our ajax call. On success we then get out Select2 instance then call the trigger of the Observer that way it by passes overwritten trigger method on your select2 instance.

The call method needs your select2 instance as the context so that the existing listeners are available to call.

var sel = $('#sel');
sel.select2(config);
sel.on('select2:selecting', onSelecting);

function onSelecting(event)
{
    $.ajax({
        type: 'POST',
        url: 'async/create_profile_category.php',
        data: {
            profile_id: '1', 
            category_id: event.params.args.data.id
        },
        success: function(event, response) {
            console.log(response);
            if (response.error === false) {
                // category assigned successfully

                // get select2 instance
                var Select2 = $users.data('select2');

                // remove prevented flag
                delete event.params.args.prevented;

                // Call trigger on the observer with select2 instance as context
                Select2.constructor.__super__.trigger.call(Select2, 'select', event.params.args);

            } else {
                // failed to assign category
                // so i want now to prevent from adding to select2
                console.log('should not add this category');
            }
        }.bind(null, event),
        error: function() {
            alert('Failed to assign category!');
        }
    });
    event.preventDefault();
    return false;
}
Prodigal answered 18/3, 2016 at 18:1 Comment(0)
U
0

here how I did it for yii2 Select2 integrated into Gridview:

    'pluginEvents' => [
    'select2:selecting' => "
    function(event) 
    { 
        var select2 = $('#types-" . $model->id . "');
        select2.select2('close');
        $.post('update',{id: " . $model->id . ", type_id: event.params.args.data.id})
        .done (function(response) 
        {
            select2.val(event.params.args.data.id);
            select2.trigger('change');
        }) 
        .fail(function(response) 
        { 
            krajeeDialog.alert('Error on update:'+response.responseText);
        });
        event.preventDefault();
        return false;
    }",
    ],

it allows to asynchoronous update data in the grid using select2 and ajax and return it to previous value if there was an error on updating.

Unthoughtof answered 8/3, 2021 at 14:21 Comment(0)
U
0

If you've prevented the default behavior of an event using e.preventDefault(), and you now want to execute your custom action but still allow the default behavior to occur, you can achieve this by using e.stopPropagation() instead of e.preventDefault().

Here's how you can modify your code:

ele.on("select2-selecting", function(e) {
    // Execute your custom action here
    
    // If you want to allow the default behavior to occur after your action,
    // use e.stopPropagation() instead of e.preventDefault()
    e.stopPropagation();
});

By using e.stopPropagation(), you're not preventing the default behavior of the event, but you're stopping its propagation further up the DOM tree. This means that your custom action will be executed, and then the event will continue its normal flow, potentially triggering any default behavior associated with it.

However, please note that using e.stopPropagation() might not always be appropriate, especially if there are other event handlers or listeners further up the DOM tree that rely on the event propagation. Make sure to consider the implications of stopping event propagation in your specific scenario.

Udela answered 20/3, 2024 at 13:35 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.