function bpFieldInitSelect2FromAjaxElement(element) {
    var form = element.closest('form');
    var $placeholder = element.attr('data-placeholder');
    var $minimumInputLength = element.attr('data-minimum-input-length');
    var $dataSource = element.attr('data-data-source');
    var $method = element.attr('data-method');
    var $fieldAttribute = element.attr('data-field-attribute');
    var $connectedEntityKeyName = element.attr('data-connected-entity-key-name');
    var $includeAllFormFields = element.attr('data-include-all-form-fields')=='false' ? false : true;
    var $allowClear = element.attr('data-column-nullable') == 'true' ? true : false;
    var $dependencies = JSON.parse(element.attr('data-dependencies'));
    var $ajaxDelay = element.attr('data-ajax-delay');
    var $isFieldInline = element.data('field-is-inline');
    var $fieldCleanName = element.attr('data-repeatable-input-name') ?? element.attr('name');

    // do not initialise select2s that have already been initialised
    if ($(element).hasClass("select2-hidden-accessible"))
    {
        return;
    }
    //init the element
    $(element).select2({
        theme: 'bootstrap',
        multiple: false,
        placeholder: $placeholder,
        minimumInputLength: $minimumInputLength,
        allowClear: $allowClear,
        dropdownParent: $isFieldInline ? $('#inline-create-dialog .modal-content') : $(document.body),
        ajax: {
            url: $dataSource,
            type: $method,
            dataType: 'json',
            delay: $ajaxDelay,
            data: function (params) {
                if ($includeAllFormFields) {
                    return {
                        q: params.term, // search term
                        page: params.page, // pagination
                        form: form.serializeArray(), // all other form inputs
                        triggeredBy: 
                        {
                            'rowNumber': element.attr('data-row-number') !== 'undefined' ? element.attr('data-row-number')-1 : false, 
                            'fieldName': $fieldCleanName
                        }
                    };
                } else {
                    return {
                        q: params.term, // search term
                        page: params.page, // pagination
                    };
                }
            },
            processResults: function (data, params) {
                params.page = params.page || 1;
                
                //if we have data.data here it means we returned a paginated instance from controller.
                //otherwise we returned one or more entries unpaginated.
                let paginate = false;

                if (data.data) {
                    paginate = data.next_page_url !== null;
                    data = data.data;
                }

                return {
                    results: $.map(data, function (item) {
                        var $itemText = processItemText(item, $fieldAttribute);
                        return {
                            text: $itemText,
                            id: item[$connectedEntityKeyName],
                        }
                    }),
                    pagination: {
                        more: paginate,
                    }
                };
            },
            cache: true
        },
    });

    // if any dependencies have been declared
    // when one of those dependencies changes value
    // reset the select2 value
    for (var i=0; i < $dependencies.length; i++) {
        var $dependency = $dependencies[i];
        //if element does not have a custom-selector attribute we use the name attribute
        if(typeof element.attr('data-custom-selector') == 'undefined') {
            form.find('[name="'+$dependency+'"], [name="'+$dependency+'[]"]').change(function(el) {
                    $(element.find('option:not([value=""])')).remove();
                    element.val(null).trigger("change");
            });
        }else{
            // we get the row number and custom selector from where element is called
            let rowNumber = element.attr('data-row-number');
            let selector = element.attr('data-custom-selector');

            // replace in the custom selector string the corresponding row and dependency name to match
            selector = selector
                .replaceAll('%DEPENDENCY%', $dependency)
                .replaceAll('%ROW%', rowNumber);

            $(selector).change(function (el) {
                $(element.find('option:not([value=""])')).remove();
                element.val(null).trigger("change");
            });
        }
    }
}

if (typeof processItemText !== 'function') {
    function processItemText(item, $fieldAttribute) {
        var $appLang = 'en';
        var $appLangFallback = 'en';
        var $emptyTranslation = '(empty)';
        var $itemField = item[$fieldAttribute];

        // try to retreive the item in app language; then fallback language; then first entry; if nothing found empty translation string
        return typeof $itemField === 'object' && $itemField !== null
            ? $itemField[$appLang] ? $itemField[$appLang] : $itemField[$appLangFallback] ? $itemField[$appLangFallback] : Object.values($itemField)[0] ? Object.values($itemField)[0] : $emptyTranslation
            : $itemField;
    }
}

