Search code examples
datatablesjquery-select2

Two Select2 in Datatable rows, the second show Add button when not results, but the first doesn't


I have a Datatables that in each rows contains two select2 for autocomplete products and units of measure. This functionality work ok, but in case of not result founds, each select2 must show Add button for launch modal dialog to insert new product or new unit of measure. The thing is that the second select2 (unit of measure column) works as expected on not results, but the first doesn't show the button. My strategy was in the Select2 language definition, make use of noResults function for create the button and bind click event. Maybe exists another way to create the button at end of the results list for the Select2, but i don't know.

I've tried the initialization of select2 in init.dt event, on createdCell and on createdRow; the result is always the same.

Summarising columns definition:

"columnDefs": [                         
                        {
                            name: "productoFactura", "targets": 1, "searchable": false, "orderable": false, width: '300px',
                            render: function (data, type, full) {
                                return `<input type="hidden" class="input-csrf-token" name="detalle_factura__token" value="${full['detalle_factura__token']}"/><select name="detalle_factura_producto_producto" class="selector-producto form-control-sm d-none" ><option value="${data.id}" selected>${data.descripcion}</option></select>`;
                            }
                        },
                        {
                            name: "unidadDeMedida", "targets": 2, "searchable": false, "orderable": false, width: '150px',
                            render: function (data, type, full) {
                                return '<select name="detalle_factura_producto_unidad_de_medida" class="selector-unidadmedida form-control-sm d-none" ><option value="' + data.id + '" selected>' + data.descripcion + '</option></select>';
                            }
                        },
                        // rest of columns definition
                    ],

Created row definition (note: with createdCell the result it's the same, also on init.dt event):

createdRow: function (row, data, dataIndex, cells) {
                        let tdProducto = $(row).find('td:eq(1)');
                        let tdUM = $(row).find('td:eq(2)');

                        $(row).find('select.selector-producto').select2({
                            theme: 'bootstrap4',
                            width: '299px',
                            dropdownParent: tdProducto,
                            minimumInputLength: 1,
                            delay: 400,
                            ajax: {
                                url: Routing.generate('producto_autocompletar'),
                                processResults: function (data) {
                                    return data;
                                }
                            },
                            language: {
                                noResults: function (term) {
                                    let g = $('#modalReader_contenedorForm').find('#prov').data('r');
                                    if (g === '0') {
                                        return "No hay resultados";
                                    }

                                    tdProducto.find('span.select2-results > ul.select2-results__options').append(`<li class="select2-results__options"><a class="btnProductoNuevo btn btn-block btn-default btn-xs text-secondary" data-src="${Routing.generate('producto_nuevo')}" data-mainform-name="producto" data-cerrar-dialogo="0" data-original-title="Registrar producto" data-modal-dialog-fullscreen="modal-fullscreen" data-modal-dialog-scrollable="modal-dialog-scrollable" data-modal-dialog-textsize="text-sm"><span class="fa fa-plus-circle"></span>&nbsp;Registrar producto</a></li>`).on('click', 'a.btnProductoNuevo', function (e) {
                                        e.preventDefault();
                                        e.stopPropagation();
                                        var target = $(this);

                                        const onCreateProductoFromFactura = function (data) {
                                            let newOption = new Option(data.producto.nombre, data.producto.id, true, true);
                                            tdProducto.find('select.selector-producto').append(newOption).trigger('change');
                                        };//select2-search__field

                                        secondModalFormV2(target, false, null, onCreateProductoFromFactura);
                                    });
                                },
                                escapeMarkup: function (markup) {
                                    return markup;
                                }
                            }
                        }).on('select2:select', function (e) {
                            let precio = e.params.data.precio;
                            let filaActual = $(tdProducto).parents('tr');
                            filaActual.find('input.input-precio:first').val(numberParser.parse(precio).toFixed(precisionPrecio));
                            recalcularImporteFila(filaActual);
                            recalcularSubtotalProductos(importeFormat);
                        });

                        $(row).find('select.selector-unidadmedida').select2({
                            theme: 'bootstrap4',
                            dropdownParent: tdUM,
                            placeholder: 'Unidad de Medidas',
                            width: '149px',
                            minimumInputLength: 1,
                            delay: 400,
                            ajax: {
                                url: Routing.generate('unidadDeMedida_autocompletar'),
                                processResults: function (data) {
                                    return data;
                                }
                            },
                            language: {
                                noResults: function () {
                                    let g = $('#modalReader_contenedorForm').find('#prov').data('r');
                                    if (g === '0') {
                                        return "No hay resultados";
                                    }

                                    tdUM.find('span.select2-results > ul.select2-results__options').append('<li class="select2-results__options"><a class="btnUnidadMedidaNuevo btn btn-block btn-default btn-xs' + (g === '0' ? 'disabled' : '') + ' text-secondary" data-src="' + Routing.generate('unidadDeMedida_nueva') + '" data-mainform-name="unidad_de_medida" data-cerrar-dialogo="1" data-original-title="Registrar Unidad de Medida"><span class="fa fa-plus-circle"></span>&nbsp;Agregar nueva</a></li>').on('click', 'a.btnUnidadMedidaNuevo', function (e) {
                                        e.preventDefault();
                                        e.stopPropagation();
                                        var target = $(this);

                                        const onUnidadDeMedidaCreated = function (data) {
                                            let newOption = new Option(data.unidadDeMedida.texto, data.unidadDeMedida.id, true, true);
                                            $(tdUM).find('select.selector-unidadmedida').append(newOption).trigger('change');
                                        }
                                        secondModalFormV2(target, false, null, onUnidadDeMedidaCreated);
                                    });

                                }
                            }
                        });
                    }

Note that the code for first Select2 it's practically the same as the second Select2, only changes in small individual aspects.

The result: Expected result

Unexpected result


Solution

  • Indeed, as I had mentioned in the question, using the definition of the Select2 language is not ideal, because the option of establishing the select2 language dynamically is lost, which in my case is also necessary. Therefore I used the select2:open and select2:close events to add and remove the button in select2. In this case there is a slight difference to my current solution: the button is always shown. This thread help me.

    So, the solution:

    createdRow: function (row, data, dataIndex, cells) {
                            let tdProducto = $(row).find('td:eq(1)');
                            let tdUM = $(row).find('td:eq(2)');
    
                            $(row).find('select.selector-producto').select2({
                                theme: 'bootstrap4',
                                width: '299px',
                                dropdownParent: tdProducto,
                                minimumInputLength: 1,
                                delay: 400,
                                ajax: {
                                    url: Routing.generate('producto_autocompletar'),
                                    processResults: function (data) {
                                        return data;
                                    }
                                },
                                language: locale
                            }).on('select2:select', function (e) {
                                let precio = e.params.data.precio;
                                let filaActual = $(tdProducto).parents('tr');
                                filaActual.find('input.input-precio:first').val(numberParser.parse(precio).toFixed(precisionPrecio));
                                recalcularImporteFila(filaActual);
                                recalcularSubtotalProductos(importeFormat);
                            }).on('select2:open', function () {
                                var a = $(this).data('select2');
                                var tdUM = $(this).parents('td');
                                if (!$('.select2-link').length) {
                                    a.$results.parents('.select2-results')
                                            .append(`<li class="btnProductoNuevoLI select2-results__options"><a class="btnProductoNuevo btn btn-block btn-default btn-xs text-secondary" data-src="${Routing.generate('producto_nuevo_v2')}" data-mainform-name="producto" data-cerrar-dialogo="0" data-original-title="Registrar producto" data-modal-dialog-fullscreen="modal-fullscreen" data-modal-dialog-scrollable="modal-dialog-scrollable" data-modal-dialog-textsize="text-sm"><span class="fa fa-plus-circle"></span>&nbsp;Registrar producto</a></li>`).on('click', 'a.btnProductoNuevo', function (e) {
                                        e.preventDefault();
                                        e.stopPropagation();
                                        var target = $(this);
    
                                        const onCreateProductoFromFactura = function (data) {
                                            let newOption = new Option(data.producto.nombre, data.producto.id, true, true);
                                            tdProducto.find('select.selector-producto').append(newOption).trigger('change');
                                        };
    
                                        secondModalFormV2(target, false, null, onCreateProductoFromFactura);
                                        a.trigger('close');
                                    });
                                }
                            }).on('select2:close', function () {
                                var a = $(this).data('select2');
                                a.$results.parents('.select2-results').find('li.btnProductoNuevoLI').remove();
                            });
    
                            $(row).find('select.selector-unidadmedida').select2({
                                theme: 'bootstrap4',
                                dropdownParent: tdUM,
                                placeholder: 'Unidad de Medidas',
                                width: '149px',
                                minimumInputLength: 1,
                                delay: 400,
                                ajax: {
                                    url: Routing.generate('unidadDeMedida_autocompletar'),
                                    processResults: function (data) {
                                        return data;
                                    }
                                },
                                language: locale
                            }).on('select2:open', function () {
                                var a = $(this).data('select2');
                                var tdUM = $(this).parents('td');
                                if (!$('.select2-link').length) {
                                    a.$results.parents('.select2-results')
                                            .append('<li class="btnUnidadMedidaNuevoLI select2-results__options"><a class="btnUnidadMedidaNuevo btn btn-block btn-default btn-xs text-secondary" data-src="' + Routing.generate('unidadDeMedida_nueva') + '" data-mainform-name="unidad_de_medida" data-cerrar-dialogo="1" data-original-title="Registrar Unidad de Medida"><span class="fa fa-plus-circle"></span>&nbsp;Agregar nueva</a></li>').on('click', 'a.btnUnidadMedidaNuevo', function (e) {
                                        e.preventDefault();
                                        e.stopPropagation();
                                        var target = $(this);
    
                                        const onUnidadDeMedidaCreated = function (data) {
                                            let newOption = new Option(data.unidadDeMedida.texto, data.unidadDeMedida.id, true, true);
                                            $(tdUM).find('select.selector-unidadmedida').append(newOption).trigger('change');
                                        }
                                        secondModalFormV2(target, false, null, onUnidadDeMedidaCreated);
                                        a.trigger('close');
                                    });
                                }
                            }).on('select2:close', function () {
                                var a = $(this).data('select2');
                                a.$results.parents('.select2-results').find('li.btnUnidadMedidaNuevoLI').remove();
                            });
                        }