Using Bootstrap Multiselect instead of Select2 for Editor

Using Bootstrap Multiselect instead of Select2 for Editor

CapamaniaCapamania Posts: 233Questions: 81Answers: 5

Hi Allan,

following up on this post https://datatables.net/forums/discussion/37049/using-bootstrap-multiselect-instead-of-select2-for-editor
I was trying to implement Bootstrap Multiselect (http://davidstutz.github.io/bootstrap-multiselect/) as Editor field type ... yet I don't get it to run. I'm using the Join-to-Many method which works fine when I either use 'checkbox' or 'select' (and multiple true). Would you happen to see what I'm missing here? (I was looking at https://editor.datatables.net/plug-ins/field-type/editor.select2 as example)


$(document).ready(function() { (function( factory ){ if ( typeof define === 'function' && define.amd ) { // AMD define( ['jquery', 'datatables', 'datatables-editor'], factory ); } else if ( typeof exports === 'object' ) { // Node / CommonJS module.exports = function ($, dt) { if ( ! $ ) { $ = require('jquery'); } factory( $, dt || $.fn.dataTable || require('datatables') ); }; } else if ( jQuery ) { // Browser standard factory( jQuery, jQuery.fn.dataTable ); } }(function( $, DataTable ) { 'use strict'; if ( ! DataTable.ext.editorFields ) { DataTable.ext.editorFields = {}; } var _fieldTypes = DataTable.Editor ? DataTable.Editor.fieldTypes : DataTable.ext.editorFields; _fieldTypes.multiselect = { _addOptions: function ( conf, opts ) { var elOpts = conf._input[0].options; elOpts.length = 0; if ( opts ) { DataTable.Editor.pairs( opts, conf.optionsPair, function ( val, label, i ) { elOpts[i] = new Option( label, val ); } ); } }, create: function ( conf ) { conf._input = $('<select/>') .attr( $.extend( { id: DataTable.Editor.safeId( conf.id ) }, conf.attr || {} ) ); var options = $.extend( { buttonWidth: '100%' }, conf.opts ); _fieldTypes.multiselect._addOptions( conf, conf.options || conf.ipOpts ); conf._input.multiselect( options ); // On open, need to have the instance update now that it is in the DOM this.on( 'open.multiselect-'+DataTable.Editor.safeId( conf.id ), function () { conf._input.multiselect( options ); } ); return conf._input[0]; }, get: function ( conf ) { var val = conf._input.val(); return conf._input.prop('multiple') && val === null ? [] : val; }, set: function ( conf, val ) { conf._input.val( val ).trigger( 'change', {editor: true} ); }, enable: function ( conf ) { $(conf._input).removeAttr( 'disabled' ); }, disable: function ( conf ) { $(conf._input).attr( 'disabled', 'disabled' ); }, // Non-standard Editor methods - custom to this plug-in inst: function ( conf ) { var args = Array.prototype.slice.call( arguments ); args.shift(); return conf._input.multiselect.apply( conf._input, args ); }, update: function ( conf, data ) { _fieldTypes.multiselect._addOptions( conf, data ); $(conf._input).trigger('change'); }, focus: function ( conf ) { conf._input.multiselect('open'); } }; })); });

This question has an accepted answers - jump to answer

Answers

  • allanallan Posts: 63,516Questions: 1Answers: 10,472 Site admin
    Answer ✓

    I don't immediately see the issue. Do you have a link to the page you are working on?

    Allan

  • CapamaniaCapamania Posts: 233Questions: 81Answers: 5
    edited November 2016

    Hi Allan ... now its running! Best Regards

  • allanallan Posts: 63,516Questions: 1Answers: 10,472 Site admin

    As in its working? If it isn't I don't see the link I'm afraid.

  • CapamaniaCapamania Posts: 233Questions: 81Answers: 5
    edited November 2016

    Hi Allan. I thought it was working fine. But I still have some issues ... like getting and setting the values correctly. Please let me know how and if I can send you link and credentials. I've sent an E-mail last week but you probably have missed it.

    What works so far is this:

    ...
    
    _fieldTypes.bootstrapmultiselect = {
        _addOptions: function ( conf, opts ) {
            var elOpts = conf._input[0].options;
    
            elOpts.length = 0;
    
            if ( opts ) {
                DataTable.Editor.pairs( opts, conf.optionsPair, function ( val, label, i ) {
                    elOpts[i] = new Option( label, val );
                } );
            }
        },
    
        create: function ( conf ) {
            var editor = this;
            conf._input = $('<select/>')
                .attr( $.extend( {
                    id: DataTable.Editor.safeId( conf.id ),
                    multiple: 'multiple'
                }, conf.attr || {} ) );
                        
            var configurations = $.extend({}, conf.opts, {
                    buttonWidth: '100%' 
                });
    
            _fieldTypes.bootstrapmultiselect._addOptions( conf, conf.options || conf.ipOpts );
    
            editor.on( 'open.bootstrapmultiselect' + DataTable.Editor.safeId( conf.id ), function () {
                conf._input.multiselect( configurations );  
            } );
    
            return conf._input[0];
        },
    
        update: function (conf, options ) {
            
            var configurations = $.extend({}, conf.opts, {
                    buttonWidth: '100%'         
                });     
            
            _fieldTypes.bootstrapmultiselect._addOptions(conf, options );
            $(conf._input).multiselect( configurations );
            
        },
    
        get: function ( conf ) {
            var val = conf._input.val();
    
            return conf._input.prop('multiple') && val === null ?
                [] :
                val;
        },
    
        set: function ( conf, val ) {
            conf._input.val( val ).trigger( 'change', {editor: true} );
        }
    
    };
    
    ...
    

    Yet and worth to mention, I'm calling the editor form with an inline button ... and one field always takes the first value of the row I clicked on ... the other field doesn't show/highlight the 'selected' values at all. Best Regards

  • allanallan Posts: 63,516Questions: 1Answers: 10,472 Site admin

    Thanks and yes, sorry I did get your e-mail but haven't had time to look in to it yet due to the number of priority support requests recently. I'll try to do so as soon as possible and get back to you.

    Allan

  • CapamaniaCapamania Posts: 233Questions: 81Answers: 5

    Thanks Allan. I reactivated the login credentials I've sent via mail shortly after your post. Best Regards

  • CapamaniaCapamania Posts: 233Questions: 81Answers: 5

    Hi Allan ... did you have a chance to take a look? :-)

  • allanallan Posts: 63,516Questions: 1Answers: 10,472 Site admin

    Is $(...).val( val ) how you change the value using Bootstrap Multiselect?

    Having a look at their documentation, instead of using that, I think you need to use .multiselect('select', value).

    Allan

  • CapamaniaCapamania Posts: 233Questions: 81Answers: 5
    edited December 2016

    Thanks for taking a look Allan. That already helped. With ...

    set: function ( conf, val ) {
           conf._input.multiselect('select', val.split(",") ).trigger( 'change', {editor: true} ); 
    }
    

    it now pre selects the options/values defined in the table. Yet ...

    1. ... if I 'edit' a field it always writes an empty value in the cell
    2. ... if I open the form again (for another row) ... it adds selected options/values from the previous row (if added options/values are not part of the then current) ... instead of showing 'just' the selected options/values for this specific row.

    E.g. if you search for 'Acatis' you see the issues. What might causes this?

  • allanallan Posts: 63,516Questions: 1Answers: 10,472 Site admin

    I'm getting:

    editor.bootstrapmultiselect.js?1480689184:108 Uncaught TypeError: Cannot read property 'split' of null(…)

    At the moment. Suggesting that val is null at that point. Perhaps it would be worth checking for null and if found make val = '';.

    if I 'edit' a field it always writes an empty value in the cell

    That suggests that the server isn't returning the value to be shown. Is it being correctly submitted?

    if I open the form again (of another row) ... it always selects the options/values of the row with the most values on which I have previously clicked on

    I'd suggest adding a deselect all API call (I saw in their documentation yesterday) before setting the current value. The impression I get is that select will just add on top of what is already selected.

    Allan

  • CapamaniaCapamania Posts: 233Questions: 81Answers: 5
    edited December 2016

    Thanks again Allan. With ...

        set: function ( conf, val ) {
            
            $(conf._input).multiselect('deselectAll', false);
            $(conf._input).multiselect('updateButtonText');
            
            if ( val == null ) {
                
                conf._input.multiselect('select', '' ).trigger( 'change', {editor: true} );
                
                } else {
                
                conf._input.multiselect('select', val.split(",") ).trigger( 'change', {editor: true} );
                
                }
        }
    

    ... the null issue and the correct pre selected values/options issue is now working. Thanks for the hints.

    Only left is submitting the values to the server correctly. The options are coming from the Editor API ->options() instance via a leftJoin table. In the mm table I see that a new record (by unique id) is created or edited ... but always with no values in the other column. How can I check what is still missing here? (If I enter the values manually in the server ... they are rendered correctly ... and the form shows the correct pre selected values now) ... I want to submit the values e.g. like this to the server: AT,DE,GB In the form with a ... alert(editor.field('myfield').val()); I see if selected that they are correct ... e.g. like AT,DE,GB

    And I see in the console that when opening the form I get 'TypeError: c[a] is undefined'

  • allanallan Posts: 63,516Questions: 1Answers: 10,472 Site admin

    If you use the field().get() method in your browser's console, will it correctly get the selected value? Also, when you submit the form to the server, does the Ajax request contain the selected value?

    Allan

  • CapamaniaCapamania Posts: 233Questions: 81Answers: 5

    Hi Allan,

    yes ... both field.get() and field.val() alert the correct and selected values:

    buttons: ( [
        { 
        label: 'Alert Field Get',
        fn: function () {
            alert(this.field('account_mm.iso_01').get());
            }
        },
        { 
        label: 'Alert Field Val',
        fn: function () {
            alert(this.field('account_mm.iso_01').val());
            }
        },
        { 
        label: 'Edit',
        fn: function () {
            this.submit();
            }
        }
    ] )
    

    But when submitting the form to the server I see in the console that the data point is "" empty.

    {"data":[{"DT_RowId":"row_2634", .... ,"account_mm"
    :{"iso_01":""},"country":{"iso_01":null}}]}
    
  • CapamaniaCapamania Posts: 233Questions: 81Answers: 5
    edited December 2016

    I also tried e.g. a preSubmit but still the field doesn't submit the data to the server although I can alert it here as well ...

    editor.on("preSubmit", function (event, data, action) {
        
        var getCountry = this.field('account_mm.iso_01').get();
        
        // via val
            this.val('account_mm.iso_01', getCountry);
        
        // via set
            this.set('account_mm.iso_01', getCountry);
        
        // Test alert
            alert(getDistribution);
    
    });
    

    Many thanks.

This discussion has been closed.