Chat GPT-generated DataTables Configs – Helpful or Risky in Production?

Chat GPT-generated DataTables Configs – Helpful or Risky in Production?

charlesrhowardcharlesrhoward Posts: 5Questions: 0Answers: 0

Hi all,

I’ve been experimenting with using ChatGPT to generate more complex DataTables configurations – for example combining serverSide, rowGroup, responsive, and buttons. It often gives me a working base really fast, especially when I don’t want to comb through the docs for every option.

But I’ve noticed something: sometimes it uses outdated syntax, or omits edge-case settings that cause issues when used in production (like incorrect ajax structure, or missing columns.render functions when needed).

So I'm curious:
- Has anyone here tried using ChatGPT (or other LLMs) to generate or validate their DataTables setup?
- Do you trust those outputs in production code?
- Are there particular config areas where AI-generated code tends to fail or mislead?

Would love to hear your experiences — especially if you've seen ChatGPT give bad advice that looked fine at first glance.

Thanks!

Replies

  • allanallan Posts: 64,660Questions: 1Answers: 10,689 Site admin

    I know plenty of people are using it to help them configure their DataTables config, so yes, without question there are people out there using such code in production.

    The flip side is that I've also seen questions where it has generated nonsense - there was one case where someone insisted a method must exist because ChatGPT said it did (it didn't and never had).

    It is a tool like any other - you need to understand it and its limitations. If you use it to generate code, personally, I think that it then needs to be reviewed so that you understand what it is doing, and why it is doing it.

    It is somewhat ironic that humans are ending up code reviewing computer generated code... :).

    Allan

  • charlesrhowardcharlesrhoward Posts: 5Questions: 0Answers: 0

    Thanks, @Allan – totally agree.

    I’ve also seen ChatGPT generate code that looks reasonable at first glance but breaks when you actually try to combine features like rowGroup with serverSide or when using custom rendering callbacks. It’s definitely helpful as a starting point, but as you said – you really need to understand and review what it’s doing.

    I like your point about humans reviewing AI-generated code – it’s funny but also kind of necessary right now.

    have you seen any particular recurring mistakes that AI tends to make when generating DataTables config?

  • allanallan Posts: 64,660Questions: 1Answers: 10,689 Site admin

    No patterns that I can really think of I'm afraid. I'll ponder that further and post back if I think of any.

    Allan

  • Loren MaxwellLoren Maxwell Posts: 449Questions: 108Answers: 10
    edited July 1

    I just wanted to chime in here and speak from an amateur's perspective on what ChatGPT was able to help me build in about an hour, which would have taken me personally much longer and probably still not have quite had the features I added to this (such as the ordering).

    I wanted to create a Feature plugin that would create filter buttons for the table based on the data.

    I wanted to pass options to it in one of two ways:

    layout: {
       topEnd: {
          filterButtons: {
             text: 'feature_code',  // Show the feature_code for the button text
             value: 'feature_tier',  // But filter on the feature_tier
             order: 'asc' // or 'desc' or null
          }
       }
    }
    

    Or

    layout: {
       topEnd: {
          filterButtons: 'feature_code'    // Show the text for and filter on the feature_code
       }
    }
    

    Below is what it produced after starting with some basic direction, a basic outline of the code, and nine prompts in total, a couple of which were to allow the passage of just a string and a couple more to add the ordering capability.

    Aside from providing the initial skeleton code, the only change I made was to create the classNames object.

    The code is functional although I haven't run it through the ringer and I do not claim it's as good as what a professional could do.

    However, a couple of things I noticed, which seem to be common occurrences when I use ChatGPT for programming:
    - It occasionally gets mixed up between DataTables 1.x and 2.x. Even after a reminder, it sometimes wanders back to the wrong version.
    - I have had the same experience Allan mentioned where it referred to methods the API does not have or it has the wrong parameters, etc.
    - Don't assume any piece of code that is currently working will be left alone in a subsequent version, even if you didn't ask anything about that specific part. Some of the changes are for the better and some are not, but either way don't assume it won't be changed.
    - It might not remember anything you've asked about before. For example, I had a previous chat about the layout, but I had to provide a code sample of what the layout looked like since it was initially writing this plugin to produce the wrong output.
    - It does a much better job than I personally do at error trapping and other such programming basics. I almost always program as though data is going to be passed along perfectly in the format that I'm expecting, but ChatGPT often builds little checks for null or undefined or whatever that I wouldn't necessarily think about or take time to address until I have an actual issue with my website.

    Overall, as an amateur ChatGPT has been great for me albeit not perfect.

    I can see why professional programmers are both worried and not worried. It advances me along in ways I wouldn't have been able to do as easily but I can also easily spot some things it runs afoul with.

    Anyway, the final code for my filterButton feature plugin is below for anyone's review and critique (and improvement!).

    Also note I told it to build the doc comment, which is a step I almost always skip in practice!

    /**
     * DataTables Feature Plugin: filterButtons
     *
     * Dynamically generates a Bootstrap 5 small button group for filtering table rows
     * based on unique values in the data. Buttons always reflect all unique values
     * from the data source, regardless of current filtering. Supports "All" to clear filter.
     * Can be used via the DataTables 2+ layout API.
     *
     * @param {object} settings - DataTables settings object (provided automatically)
     * @param {string|object} opts - Either a string (the property for both label and value)
     *   or an object with the following properties:
     *   @param {string} [opts.text]  - Property to use as the button label.
     *   @param {string} [opts.value] - Property to use as the button filter value.
     *   @param {'asc'|'desc'|null} [opts.order] - Sort order for buttons by label
     *       ('asc' for ascending, 'desc' for descending, null for no sort).
     *
     * @returns {HTMLElement} - A Bootstrap 5 button group DOM element to be placed
     *   in the DataTable's layout, containing filter buttons for all unique values.
     *
     * @example
     * // As a string (uses same property for label and value)
     * layout: {
     *   topEnd: {
     *     filterButtons: 'status'
     *   }
     * }
     *
     * @example
     * // As an object (distinct label/value fields, sorted ascending)
     * layout: {
     *   topEnd: {
     *     filterButtons: {
     *       text: 'school_name',
     *       value: 'school_code',
     *       order: 'asc'
     *     }
     *   }
     * }
     *
     * Features:
     * - Buttons are always built from all data, not just filtered/visible rows.
     * - Includes an "All" button to clear the filter.
     * - Filters are applied using a DataTables global search function,
     *   filtering at the row data level (not dependent on column visibility).
     * - Supports DataTables 2.x and 1.10+.
     *
     * Limitations:
     * - Assumes each row's data is a flat object.
     * - Only supports single-field filtering at a time.
     */
    DataTable.feature.register('filterButtons', function (settings, opts) {
        // Allow string, object, or object with order
        let options;
        if (typeof opts === 'string') {
            options = { text: opts, value: opts, order: null };
        } else if (typeof opts === 'object' && opts !== null) {
            options = Object.assign({ text: false, value: false, order: null }, opts);
            if (!options.value) options.value = options.text;
        } else {
            throw new Error("filterButtons: Pass a string or object with 'text' and/or 'value'.");
        }
        
        const classNames = {
            container: 'btn-group btn-group-sm mb-3',
            buttonAll: 'btn btn-outline-secondary fs-xs',
            buttonFilter: 'btn btn-outline-primary fs-xs'
        }
    
        const container = document.createElement('div');
        container.className = classNames.container;
        container.role = "group";
    
        const api = new DataTable.Api(settings);
        let activeFilter = null;
    
        const filterFn = function(settingsArg, data, dataIndex, rowData) {
            if (settingsArg !== settings) return true;
            if (!activeFilter) return true;
            const row = rowData || api.row(dataIndex).data();
            if (!row) return true;
            return row[options.value] == activeFilter;
        };
    
        DataTable.ext.search.push(filterFn);
    
        api.on('destroy', function() {
            const idx = DataTable.ext.search.indexOf(filterFn);
            if (idx !== -1) DataTable.ext.search.splice(idx, 1);
        });
    
        // Get all unique (value, label) pairs and order them as requested
        function buildFilterArray() {
            const unique = {};
            api.data().each(function (row) {
                const label = row[options.text];
                const value = row[options.value];
                if (label !== undefined && value !== undefined) unique[value] = label;
            });
            let arr = Object.entries(unique).map(([value, label]) => ({ label, value }));
    
            // Order, if requested
            if (options.order === 'asc') {
                arr.sort((a, b) => a.label.localeCompare(b.label, undefined, {numeric:true}));
            } else if (options.order === 'desc') {
                arr.sort((a, b) => b.label.localeCompare(a.label, undefined, {numeric:true}));
            }
            return arr;
        }
    
        function renderButtons() {
            container.innerHTML = '';
            const filterArray = buildFilterArray();
    
            // "All" button
            const allBtn = document.createElement('button');
            allBtn.type = "button";
            allBtn.className = classNames.buttonAll;
            allBtn.textContent = "All";
            allBtn.addEventListener('click', function () {
                activeFilter = null;
                highlightButtons();
                api.draw();
            });
            container.appendChild(allBtn);
    
            filterArray.forEach(obj => {
                const btn = document.createElement('button');
                btn.type = "button";
                btn.className = classNames.buttonFilter;
                btn.textContent = obj.label;
                btn.dataset.filterValue = obj.value;
    
                btn.addEventListener('click', function () {
                    activeFilter = obj.value;
                    highlightButtons();
                    api.draw();
                });
    
                container.appendChild(btn);
            });
    
            highlightButtons();
        }
    
        function highlightButtons() {
            Array.from(container.children).forEach(btn => {
                if (btn.dataset.filterValue == activeFilter) {
                    btn.classList.add('active');
                } else if (!activeFilter && btn.textContent === "All") {
                    btn.classList.add('active');
                } else {
                    btn.classList.remove('active');
                }
            });
        }
    
        api.on('draw', renderButtons);
        renderButtons();
    
        return container;
    });
    
  • Loren MaxwellLoren Maxwell Posts: 449Questions: 108Answers: 10
    edited July 1

    Occurred to me I should add a picture of the final product.

    Also I should note that I did not initially ask for the "All" button, ChatGPT just included it, but I liked it so I kept it.

    That's another observation -- sometimes it will offer me something I hadn't even thought of.

  • allanallan Posts: 64,660Questions: 1Answers: 10,689 Site admin

    Awesome! It's great to get some first hand feedback :)

    Allan

  • charlesrhowardcharlesrhoward Posts: 5Questions: 0Answers: 0

    @Loren Maxwell Ich weiß das wirklich zu schätzen. Es ist so klar.

Sign In or Register to comment.