Mason Mason - 6 months ago 35
MySQL Question

Getting stuck in a loop on .change - Select2 Drop Down Lists

I have 2 drop down lists. One for people and one for businesses. If you select a person from the list it will automatically query the database and then select the correct corresponding business that is associated with that person. If you select a business, it will automatically query the database for all the people that are associated with that company. Then it clears the current list of people and appends the associated people.

This is all works great...until I wanted to use Select2 to make my drop down lists easily searchable. I now get stuck in an infinite loop because the Select2 uses the .val().trigger('change') method to select the value you want. When that's triggered it also triggers the .change function that runs the queries and populates the fields.

What can I do to fix this?

Here is my code:

$('#personNameField').select2();
$('#businessNameField').select2();

/* When a business is selected it then pulls all the associated customers and puts them into the customer name drop down list */
$("#businessNameField").change(function getAssociatedPeople() {
var sitePath = sitepath.sitePath;
var business_id = $("#businessNameField").val();
if (business_id == 'Choose a Company') {
$('#personNameField').val('Choose a Person').trigger('change');
}
else {
/* Location of the query script that pulls info from the database */
var url = myticketsscript.pluginsUrl + '/portal/public/includes/shortcodes/my-tickets/auto-complete/auto-complete.php';
$.get( url, { business_id: business_id, sitePath: sitePath } )
.done(function( data ) {
$('#personNameField').html('<option value="Choose a Person">Choose a Person</option>');
var results = jQuery.parseJSON(data);
console.log(data);
$(results).each(function(key, value) {

/* Add the data to the customer name drop down list */

$('#personNameField').append('<option id="customer_id" value="'+ value.id +'">' + value.first_name + ' ' + value.last_name + '</option>');

/* Logs the data in the console */
console.log(key);
console.log(value);
})
});
}
});
/* When a person is selected it then pulls all the associated business and puts it into the business name drop down list */
$("#personNameField").change(function() {
var customer_id = $("#personNameField").val();
var sitePath = sitepath.sitePath;
if (customer_id == 'Choose a Person') {
var url = myticketsscript.pluginsUrl + '/portal/public/includes/shortcodes/my-tickets/auto-complete/auto-complete.php';
$.get( url, { customer_list: customer_id, sitePath: sitePath } )
.done(function( data ) {
$('#businessNameField').val('Choose a Company').trigger('change');
$('#personNameField').html('<option value="Choose a Person">Choose a Person</option>');
var results = jQuery.parseJSON(data);
console.log(data);
$(results).each(function(key, value) {

/* Add the data to the customer name drop down list */
$('#personNameField').append('<option id="customer_id" value="'+ value.id +'">' + value.first_name + ' ' + value.last_name + '</option>');

/* Logs the data in the console */
console.log(key);
console.log(value);
})
});
}
else {
/* Location of the query script that pulls info from the database */
var url = myticketsscript.pluginsUrl + '/portal/public/includes/shortcodes/my-tickets/auto-complete/auto-complete.php';
$.get( url, { customer_id: customer_id, sitePath: sitePath } )
.done(function( data ) {
var results = jQuery.parseJSON(data);
console.log(data);
$(results).each(function(key, value) {

/* Selects the correct company for the customer selected */

$('#businessNameField').val(value.id).trigger('change');

console.log(key);
console.log(value);
})
});
}
});

Answer

Not having used Select2 before myself, I looked into their docs and found that they have some of their own events.

https://select2.github.io/examples.html#programmatic-control

So rather than binding the selectors to change, perhaps you want to try something like:

$("#businessNameField").on("select2:select", function () {...});
$("#personNameField").on("select2:select", function () {...});

I just tried it on this little example below. I got the infinite loop when using change, but once I used the proper events, it didn't loop.

Note that I navigated the nested object to get at the value and text of each select option; e.params.data.id and e.params.data.text, where e is the event passed to the callback.

It's kind of a silly little example where selecting one option will arbitrarily select an option in the other select, but you get the idea. Hope this helps.

<!DOCTYPE html>
<html>
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script>
<script type="text/javascript">
    $(document).ready(function() {
        var firstSelect = $(".js-example-basic-single1")
        firstSelect.select2();

        var secondSelect = $(".js-example-basic-single2")
        secondSelect.select2();

        firstSelect.on("select2:select", function (e) {
            var value = e.params.data.id;
            var text = e.params.data.text;
            console.log("firstSelect selected value: " + value);

            if (value === "AL") {
                secondSelect.val("MA").trigger("change");
            }
            else if (value === "WY") {
                secondSelect.val("CA").trigger("change");
            }
        });

        secondSelect.on("select2:select", function (e) {
            var value = e.params.data.id;
            var text = e.params.data.text;
            console.log("secondSelect selected value: " + value);

            if (value === "MA") {
                secondSelect.val("AL").trigger("change");
            }
            else if (value === "CA") {
                secondSelect.val("WY").trigger("change");
            }
        });
    });
</script>
</head>
<body>
<select class="js-example-basic-single1">
    <option value="Default">Default</option>
    <option value="AL">Alabama</option>
    <option value="WY">Wyoming</option>
</select>
<select class="js-example-basic-single2">
    <option value="Default">Default</option>
    <option value="MA">Massachusetts</option>
    <option value="CA">California</option>
</select>
</body>
</html>