string-based index for configuration/examples

string-based index for configuration/examples

tacman1123tacman1123 Posts: 227Questions: 52Answers: 1

Most of the examples use an index to configure a column

new DataTable('#myTable', {
    columnControl: [
        {
            target: 0,
            content: ['order']
        },
        {
            target: 1,
            content: ['search']
        }
    ],
    ordering: {
        handler: false,
        indicators: false
    }
});

Since my columns are often dynamic (e.g. based on permissions), I don't know the column index. What I'd rather have is a column key. Or most of the time I use columnDef, where the configuration is embedded in the column.

But the documentation is mostly like this, where the plugins are added to columns by index.

Two approaches:

  • When defining the column, add the control.
  • Allow configuring the plugin with column codes rather than keys.
columnControl: [
        {
            target: 'lastName',
            content: ['order']
        },
        {
            target: 'bio',
            content: ['search']
        },

]

Since version 3 is in beta, I figured it'd be a good time to revive this. I know I asked about it a few years ago, and as I recall, all the plugins can be configured at the column level with columnDefs.

It would help me if the docs made that more obvious, and it'd probably help AI Agents code better for the same reason, not needed to separately track numeric column indexes.

Replies

  • allanallan Posts: 65,710Questions: 1Answers: 10,928 Site admin

    The columnControl.target option is actually about which row in the header or footer the content will apply to - not the column.

    For column specific configuration with ColumnControl you need to use columns or columnDefs. In this case, the latter would be the solution for you as you can use names to target columns.

    For example:

    new DataTable('#myTable', {
        columns: [
            { name: 'person' },
            { name: 'location' },
            { name: 'position' }
            { name: 'action' }
        ],
        columnDefs: [
            {
                targets: 'action:name',
                columnControl: ['order']
            }
        ],
        columnControl: ['order', 'search']
    });
    

    It can get a little complicated if you have multiple rows for ColumnControl, since you need to specify it for both the global configuration and any override - e.g.:

    new DataTable('#myTable', {
        columns: [
            { name: 'person' },
            { name: 'location' },
            { name: 'position' }
            { name: 'action' }
        ],
        columnDefs: [
            {
                targets: 'action:name',
                columnControl: {
                    target: 1,
                    content: [] // no search for the action column
                }
            }
        ],
        columnControl: [
            {
                target: 0,
                content: ['order'],
            },
            {
                target: 1,
                content: ['search']
            }
        ]
    });
    

    Allan

  • tacman1123tacman1123 Posts: 227Questions: 52Answers: 1

    Thanks! I'll have to re-read the docs, as I'm still finding it confusing. I only use ajax (candidate for rename in version 3!) Claude helped me articulate my idea.

    Feature suggestion: object-keyed columns config as an alternative to array + columnDefs

    With v3 in beta, I wanted to float an ergonomic suggestion for column configuration. The current pattern works, but it splits column identity and column behavior across two arrays:

    new DataTable('#myTable', {
       columns: [
           { name: 'person' },
           { name: 'location' },
           { name: 'position' },
           { name: 'action' }
       ],
       columnDefs: [
           {
               targets: 'action:name',
               columnControl: ['order']
           }
       ],
       columnControl: ['order', 'search']
    });
    

    The friction here:

    1. Every column needs a name property even when nothing else is being configured.
    2. To override one column's behavior, you jump to a separate columnDefs array and use a selector (targets: 'action:name') to point back at the column you just defined.
    3. The top-level columnControl acts as a default for all columns, but that "this is a default" relationship is implicit.

    Proposal: allow columns to be an object keyed by column name

    new DataTable('#myTable', {
       defaults: {
           columnControl: ['order', 'search']
       },
       columns: {
           person:   {},
           location: {},
           position: {},
           action:   { columnControl: ['order'] }
       }
    });
    

    What changes:

    • Keys are names. No more repeating name: 'person'. The key serves as the identifier.
    • Per-column overrides live with the column. No selector indirection — the action entry declares its own columnControl inline.
    • defaults makes the fallback relationship explicit. Top-level options that apply per-column can move under defaults, so it's clear at a glance that they're overridable.

    The existing array form would obviously stay supported — this would just be an alternative shape that the config normalizer accepts.

    On property order

    JavaScript object property order is well-defined for string keys (ES2015+, fully spec'd across operations in ES2020). Non-integer string keys iterate in insertion order, which is exactly what column names are. So person, location, position, action is preserved deterministically.

    The one caveat is integer-like string keys ("0", "1", etc.) — those get sorted numerically and float to the front of iteration. Not a real concern for column names, but worth documenting if this lands. If anyone's keying columns by something numeric-looking, they'd want to stick with the array form.

    JSON config files are a separate consideration. The JSON spec says objects are unordered, even though every mainstream parser preserves insertion order in practice. For configs that round-trip through JSON or external tools, the array form would remain the safer choice — which is another reason to keep it supported rather than replace it.

    Why bother

    For tables with a lot of columns where most use defaults and only a few need overrides, the object form is significantly more readable. The diff between "this column is configured" and "this column uses defaults" becomes visible at a glance, instead of requiring a scan across two arrays plus a mental selector lookup.

    Curious whether this fits the direction v3 is heading, or whether there's a reason the array form is preferred that I'm not seeing.

  • allanallan Posts: 65,710Questions: 1Answers: 10,928 Site admin

    Interesting idea - thank you for this. I haven't spent much time exploring the possibility of using columns as an object, primarily due to the property order that you indicate. I actually wasn't aware (or had forgotten) that the key order is well defined now, so using a property key name as a shorthand for name: key might indeed be viable.

    I hadn't planned to adding much more to DataTables 3, but perhaps there is room for this. I'm concerned that the JSON aspect is a footgun though - I can see things going wrong there.

    It is worth nothing that in your example you can do the following since you know the order of the columns:

    new DataTable('#myTable', {
       columns: [
           { name: 'person' },
           { name: 'location' },
           { name: 'position' },
           { name: 'action', columnControl: ['order'] }
       ],
       columnControl: ['order', 'search']
    });
    

    However, I take the point that you might want columns to only assign the name and all the other configuration could be done separately, which I think is the thrust of what you want?

    For that, perhaps this could be a valid approach - then the column order can trivially be changed, or columns such as action removed if needed while the main configuration stays untouched:

    new DataTable('#myTable', {
       columns: [ 'person', 'location', 'position', 'action' ].map(n => ({name: n})),
       columnDefs: [
           {
               targets: 'action:name',
               columnControl: ['order']
           }
       ],
       columnControl: ['order', 'search']
    });
    

    Perhaps an option would be to allow the values in the columns array to be a string and that would map to the name - so my example above would be simply:

    new DataTable('#myTable', {
       columns: [ 'person', 'location', 'position', 'action' ],
       columnDefs: [
           {
               targets: 'action:name',
               columnControl: ['order']
           }
       ],
       columnControl: ['order', 'search']
    });
    

    There could be an argument for that to apply to columns.data as well as columns.name.

    Allan

Sign In or Register to comment.