Search code examples
javascriptjqueryajaxjquery-chosenajaxform

Chosen.js : automatically select freshly created value in ajax callback


I have this code in ajax :

Main function

    $.ajax({
        type:"POST",
        url:dest_url,
        data:$(this).serialize(),
        dataType: 'json',
        success: function(data){
            if($.isEmptyObject(data.error)){
                listRefresh(data.id);
                $('#site_id').val(data.id).trigger("chosen:updated");
            }else{
                console.log(data.error);
            }
        },
        error: function(data){

        }
    }
})

Function listRefresh()

function listRefresh(id){
    $('#site_id_chosen').hide().parent().append('<i class="fa fa-circle-o-notch fa-spin"></i>');
    $.ajaxSetup({
        header:$('meta[name="_token"]').attr('content')
    })
    var src_url = location.href + '?sites='+id;
    $.ajax({
        url: location.href,
        type: 'GET',
        cache: false
    })
    .done(function(id) {
        $('.panel-heading').load(src_url + " .panel-heading >*");
        $('#site_id').load(src_url+ " #site_id >*", function(id) {
            $('.fa-spin').remove();
            $('#site_id_chosen').show();
        }).val(id).trigger("chosen:updated");
    })
    .fail(function() {
        $('#site_id').load(location.href+ " #site_id >*", function() {
            $(this).val('').trigger("chosen:updated");
            $('.fa-spin').remove();
            $('#site_id_chosen').show();
        });
    });
}

All works fine except the update of chosen selected value. When I do console.log(data.id);,it works. When I do $('#site_id').val(40).trigger("chosen:updated"); from the console, it works.

I thought it was because ajax is asynchronous, but my code is in the success callback, so data.id should be defined...

I also tried to update chosen selected value in listRefresh() function, but nothing works.

EDIT

It's still not working, I don't know why... Here is my full code, updated with yours :

//Création d'un nouveau site en ajax
    $('#creer-site form').on('submit',function(e){
        var base = "{{ url('/') }}";
        var dest_url = base + '/sites'; 
        $.ajaxSetup({
            header:$('meta[name="_token"]').attr('content')
        })
        e.preventDefault(e);
        $.ajax({
            type:"POST",
            url:dest_url,
            data:$(this).serialize(),
            dataType: 'json',
            success: function(data){
                if($.isEmptyObject(data.error)){
                    console.log(data);
                    $('.alert').remove();
                    $('.modal').modal('hide');
                    successHtml = '<div class="alert alert-success alert-dismissible" role="alert"><button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span><span class="sr-only">Fermer</span></button><span class="fa fa-check fa-lg"></span>';
                    successHtml += data.message;
                    successHtml += '</div>';
                    $('.header-container').after( successHtml );
                    listRefresh(data.id); // on rafraichit la liste et on sélectionne l'objet nouvellement créé
                }else{
                    console.log(data.error);
                }
            },
            error: function(data){
                $('.alert').remove();
                $('.modal').animate({ scrollTop: 0 }, 'fast');
                errorsHtml = '<div class="alert alert-danger"><span class="fa fa-warning fa-lg"></span><strong> Une ou plusieurs erreurs ont été detectées :</strong><ul>';
                $.each(data.responseJSON, function(key, value) {
                    errorsHtml += '<li>' + value + '</li>';
                });
                errorsHtml += '</ul></div>';
                $('#creer-site form').prepend( errorsHtml );
            }
        })
    });

    // on rafraichit la liste et on sélectionne l'objet nouvellement créé
    function listRefresh(id){
        $('#site_id_chosen').hide().parent().append('<i class="fa fa-circle-o-notch fa-spin"></i>');
        $.ajaxSetup({
            header:$('meta[name="_token"]').attr('content')
        })
        var src_url = location.href + '?sites='+id;
        $.ajax({
            url: location.href,
            type: 'GET',
            cache: false
        })
        .done(function(id) {
            $('.panel-heading').load(src_url + " .panel-heading >*");
            $("#site_id").chosen("destroy");
            $('#site_id').load(src_url+ " #site_id >*", function(id) {
                $("#site_id").chosen({
                    no_results_text: "Aucun résultat pour ", 
                    search_contains: true, 
                    placeholder_text_single: "Sélectionner...", 
                    allow_single_deselect:true, 
                    width: "300px"
                }).val(id).trigger("chosen:updated");
                $('.fa-spin').remove();
                $('#site_id_chosen').show();
            });
        })
        .fail(function() {
            $('#site_id').load(location.href+ " #site_id >*", function() {
                $(this).val('').trigger("chosen:updated");
                $('.fa-spin').remove();
                $('#site_id_chosen').show();
            });
        });
    }

EDIT 2

For some reason the js variable is lost during the ajax call, according to the debugs : when I watch 'id' variable, it changes to 'undefined' at the exact moment the function starts the ajax call.

A temporary solution would be to write id in a hidden input, this way I could get it in ajax call again (it perfectly works), but that's very ugly...

If you have a better solution, and maybe an explanation of why the variable is lost, I would be grateful :)

Edit 3

The solution to my latest "bug" is here : Variable lost in ajax request


Solution

  • Your issue is in this fragment:

    $('#site_id').load(src_url+ " #site_id >*", function(id) {
            $('.fa-spin').remove();
            $('#site_id_chosen').show();
     }).val(id).trigger("chosen:updated");
    

    The val(id) is applied immediately while the load method runs in the future. Moreover, you already call the same method in the main ajax.

    Hence I suggest to move this line:

    $('#site_id').val(data.id).trigger("chosen:updated");
    

    inside the success load method callback.

    The load method gets data from the server and place the returned HTML into the matched element (i.e.: always site_id). From the code, without any info about your html, I assume the load fanction overwrites your chosen element. This means you need to recreate a new instance on the new element and remove the previous one. This are the two following actions:

    1. $("#site_id").chosen("destroy"); before loading
    2. $("#site_id").chosen({...your options..}).val(data.id).trigger("chosen:updated"); in success load callback

    Your code will be:

    $.ajax({
        type: "POST",
        url: dest_url,
        data: $(this).serialize(),
        dataType: 'json',
        success: function (data) {
            if ($.isEmptyObject(data.error)) {
                listRefresh(data.id);
            } else {
                console.log(data.error);
            }
        },
        error: function (data) {
    
        }
    })
    function listRefresh(id) {
        $('#site_id_chosen').hide().parent().append('<i class="fa fa-circle-o-notch fa-spin"></i>');
        $.ajaxSetup({
            header: $('meta[name="_token"]').attr('content')
        })
        var src_url = location.href + '?sites=' + id;
        $.ajax({
            url: location.href,
            type: 'GET',
            cache: false
        }).done(function (data) {
            $('.panel-heading').load(src_url + " .panel-heading >*");
            // 
            // remove chosen:
            //
            $("#site_id").chosen("destroy");
            $('#site_id').load(src_url + " #site_id >*", function (data) {
                //
                // next row added
                //
                $("#site_id").chosen({...your options..}).val(id).trigger("chosen:updated");
                $('.fa-spin').remove();
                $('#site_id_chosen').show();
            }); // USELESS  .val(id).trigger("chosen:updated");
        }).fail(function () {
            $('#site_id').load(location.href + " #site_id >*", function () {
                $(this).val('').trigger("chosen:updated");
                $('.fa-spin').remove();
                $('#site_id_chosen').show();
            });
        });
    }