Editor Field Plugin

Editor Field Plugin

mguinnessmguinness Posts: 85Questions: 12Answers: 1

There are already several Field type plug-ins for Editor. I came across International Telephone Input control which seems like it could be a nice addition.

Maybe this could be added as a field type plugin for Editor? I don't have the requisite skills to create a custom plug-in, but maybe someone else can.

This question has an accepted answers - jump to answer

Answers

  • allanallan Posts: 61,446Questions: 1Answers: 10,054 Site admin

    You can actually do this one without the need for a plug-in, since it works by just giving it an input element to work with. You can get that for a field using the field().input() method - here is an example: http://live.datatables.net/nuvihosi/92/edit .

    Nice input library that - thanks for introducing me to it.

    Allan

  • mguinnessmguinness Posts: 85Questions: 12Answers: 1

    Thanks Allan. Although on the surface that appears to work, it doesn't when using it in conjunction with libphonenumber and storing numbers in the database as E.164 standard.

    The reason is that when using that library you need to use Public Methods getNumber() and setNumber() for the country selection and formatting to work. See crude example below:

    http://live.datatables.net/yomenika/1/edit?js,console,output

    If developed using plug-in interface I see that the getNumber() and setNumber() functions would map nicely with the get() and set() functions of the plugin.

    There is a hiddenInput Initialisation Option though that would add complexity, but I'm open to suggestions on getting this working.

  • allanallan Posts: 61,446Questions: 1Answers: 10,054 Site admin

    Ah - yes, if you need to use methods such as getNumber and setNumber, then a field type plug-in would be the way to do it.

    I've made a little attempt at it: http://live.datatables.net/qicamepe/1/edit .

    But the getNumber() method is always giving me an empty string. Have you used this input elsewhere? Perhaps you can see something daft I've done?

    Allan

  • mguinnessmguinness Posts: 85Questions: 12Answers: 1
    edited April 2021

    Thanks so much for looking into this further. From a quick look I think you missed adding the Utilities Script. I just added the following to the HTML and it appears to work now.

    <script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.12/js/utils.min.js"></script>

    BTW, you can also format the phone number in the grid with formatNumber function.

    {
      "data": "tel", "render": function (data, type, row, meta) {
        return intlTelInputUtils.formatNumber(data, null, intlTelInputUtils.numberFormat.NATIONAL);
      }
    }
    
  • mguinnessmguinness Posts: 85Questions: 12Answers: 1

    I changed the field definition to also pass initialization options to the control.

    fields: [
        {
            label: "Telephone number:",
            name: "tel",
            type: 'telephone',
            opts: {
                preferredCountries: [],
                onlyCountries: ['au', 'ca', 'nz', 'gb', 'us'],
                initialCountry: 'us'
            }
        }
    ]
    

    I also added the close event since the initial country wasn't getting reset when the editor closed - it would stay on the last selected country.

    DataTable.ext.editorFields.telephone = {
        create: function (conf) {
            conf._input = $('<input>');
    
            this.one('open', function () {
                var options = $.extend({
                    dropdownContainer: document.body
                }, conf.opts);
    
                conf._tel = intlTelInput(conf._input[0], options);
    
                if (conf._initSet) {
                    conf._tel.setNumber(conf._initSet);
                }
            });
    
            this.on('close', function () {
                conf._tel.setCountry(conf.opts.initialCountry || '');
            });
    
            return conf._input[0];
        },
    
        get: function (conf) {
            return conf._tel.getNumber();
        },
    
        set: function (conf, val) {
            if (!conf._tel) {
                conf._initSet = val;
            }
            else {
                conf._tel.setNumber(val);
            }
        }
    };
    

    This seems to be working well, hopefully others will find it useful. I think this would be a good field type plug-in addition as it's such a common use case.

  • allanallan Posts: 61,446Questions: 1Answers: 10,054 Site admin
    Answer ✓

    That's very cool - many thanks! I'll get it added into the list :).

    Allan

  • mguinnessmguinness Posts: 85Questions: 12Answers: 1

    Below is my attempt to cobble together a plugin:

    /**
     * Use the [International Telephone Input](https://intl-tel-input.com/) telephone input control in Editor.
     */
    
    (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.telephone = {
        create: function (conf) {
            conf._input = $('<input>');
    
            this.one('open', function () {
                var options = $.extend({
                    dropdownContainer: document.body
                }, conf.opts);
    
                conf._tel = conf._input.intlTelInput(options);
    
                if (conf._initSet) {
                    conf._tel.intlTelInput('setNumber', conf._initSet);
                }
            });
    
            return conf._input[0];
        },
    
        get: function (conf) {
            return conf._tel.intlTelInput('getNumber', intlTelInputUtils.numberFormat.INTERNATIONAL);
        },
    
        set: function (conf, val) {
            if (!conf._tel) {
                conf._initSet = val;
            }
            else {
                conf._tel.intlTelInput('setCountry', conf.opts.initialCountry || '');
                conf._tel.intlTelInput('setNumber', val);
            }
        },
    
        enable: function ( conf ) {},
    
        disable: function ( conf ) {},
    
        destroy: function (conf) {
            this.off( 'open' );
        }
    };
    
    
    }));
    

    You need to include the following into your HTML:

    <link href="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.12/css/intlTelInput.min.css" type="text/css" />
    
    <style>
        .iti.iti--allow-dropdown {
            width: 100%;
        }
    </style>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.12/js/intlTelInput-jquery.min.js" type="text/javascript"></script>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.12/js/utils.min.js" type="text/javascript"></script>
    

    Below is an example field configuration:

    {
        label: "Telephone number:",
        name: "tel",
        type: "telephone",
        opts: {
            initialCountry: 'us'
        }
    }
    
  • allanallan Posts: 61,446Questions: 1Answers: 10,054 Site admin

    Nice one - thanks for sharing that with us!

    Allan

  • TechCoderTechCoder Posts: 4Questions: 1Answers: 0
    edited December 2021

    This works great for what it does, but I need to also use other Public Methods, in particular
    getValidationError() - to validate the number fits the selected country format
    getNumberType() - to validate it is a mobile/other type

    In the documentation it is clear how to access the instance again (for instance, in using
    getInstance(input)

    However, as this example never actually initialises the plugin, there is nothing to call there.

    Prior to finding this plugin method, I had things 'sort of' working - at least I could get the errors returned using the ClientValidation

    https://editor.datatables.net/examples/api/clientValidation.html

    using this code...

     editor.on('initSubmit', function (e, o, action) {
                if (action !== 'remove') {
                    var input = this.field('driverMobilePhone');
                    var iti = intlTelInput(input);
                    var error = iti.getValidationError();
                    if (error) {
                        driverMobilePhone.error(error);
                    }
                    // Only validate user input values - different values indicate that
                    // the end user has not entered a value
                    if (!driverMobilePhone.isMultiValue()) {
                        if (!driverMobilePhone.val()) {
                            driverMobilePhone.error('A Driver Mobile Number must be given');
                        }
                    }
    
                    // ... additional validation rules
    
                    // If any error was reported, cancel the submission so it can be corrected
                    if (this.inError()) {
                        return false;
                    }
                }
            });
    

    Though, now, I'm not sure how to get the 'input' var with the plugin (maybe it is the long hours on the project - after not working much for the last couple years I'm a bit out of practice! :)

    Edited by Colin - Syntax highlighting. Details on how to highlight code using markdown can be found in this guide.

  • allanallan Posts: 61,446Questions: 1Answers: 10,054 Site admin

    field().input() will automatically pick out any input, select or textarea elements inside a field - so you could use:

    this.field('driverModilePhone').input()
    

    Allan

Sign In or Register to comment.