columns.render string "FunctionName()" function notation broken

columns.render string "FunctionName()" function notation broken

infogulchinfogulch Posts: 2Questions: 2Answers: 0

According to the documentation at columns.render (see Types > string > function notation) you should be able able to specify the name of a function in the render field followed by a pair of parens to have datatables call the named function with the data to render the field.

I have set up a jsfiddle, but it's not working: http://jsfiddle.net/jECkP/40/

Specifically I get TypeError: data[a[i]] is not a function error in the console, and nothing is rendered. I would expect it to render the data of the field by calling the named function.

The source code that corresponds with this error is in _fnGetObjectDataFn core.data.js#L286, where the specific code is:

// a is ["FunctionName"], i is 0, and data is the data of the field, e.g. "foo"
data = data[ a[i] ]();

Any ideas?

This question has an accepted answers - jump to answer

Answers

  • allanallan Posts: 63,538Questions: 1Answers: 10,476 Site admin
    Answer ✓

    Good question. I'm afraid the documentation might have mislead you slightly here. What it really means is that it can execute a function in the data source object, not some random function.

    e.g.

    var data = [
      {
         name: function () { ... }
      }
    ]
    

    could be used.

    However it is actually relatively straight forward to get your code working with a little anonymous function:

          render: function(data) {
            return FunctionName(data);
          }
    

    https://jsfiddle.net/jECkP/42/

    Allan

  • infogulchinfogulch Posts: 2Questions: 2Answers: 0

    Thank you for the clarification!

    That makes a lot more sense than my interpretation, though the linked jsfiddle doesn't really apply. What you linked uses the standard function type renderer. I'm talking about a string that uses function notation. Here's the quote:

    () - Function notation. Adding () to the end of a parameter will execute a function of the name given. For example: browser() for a simple function on the data source, browser.version() for a function in a nested property or even browser().version to get an object property if the function called returns an object. Note that function notation is recommended for use in columns.render rather than columns.data as it is much simpler to use as a renderer.

    Here is a revised example of a use of the feature I'm talking about: https://jsfiddle.net/jECkP/46/

    Specifically, in each data row, if a key contains a map of functions, you can use { name: "fnMap", render: "MyFn()" } to call data[i].fnMap.MyFn(). Honestly I'm struggling to find a good use case for this (I'm just curious at this point).

  • infogulchinfogulch Posts: 2Questions: 2Answers: 0

    Thanks for the clarification!

    Yeah I misinterpreted the purpose, but the jsfiddle you linked uses the standard function-type renderer, wheras I'm talking about a string-type renderer, where the key is in the form of render: "X()" where X is the name of a function. Here's the quote from the docs:

    String:
    ...
    () - Function notation. Adding () to the end of a parameter will execute a function of the name given. For example: browser() for a simple function on the data source, browser.version() for a function in a nested property or even browser().version to get an object property if the function called returns an object. Note that function notation is recommended for use in columns.render rather than columns.data as it is much simpler to use as a renderer.

    Here's an updated jsfiddle that uses the feature I'm talking about: https://jsfiddle.net/jECkP/46/

    Specifically, if the column definition is {title:"title", data:"fnmap", render:"MyFn()"} then when the cell is rendered, it will call data[i].fnmap.MyFn(). Honestly I'm struggling to come up with a use case for this, just out of sheer curiosity.

  • allanallan Posts: 63,538Questions: 1Answers: 10,476 Site admin

    Honestly I'm struggling to come up with a use case for this, just out of sheer curiosity.

    Its basically useless if you just have an array of plain objects being shown in the table, but if you had an array of "class" instances it is useful - for example:

    data = [
      new Person( "Allan" ),
      new Person( "Fred" )
    ]
    

    where Person is defined as:

    function Person( name ) {
      var _name = name;
    
      this.name = function () {
        return _name; // getter only here - would need a setter as well
      }
    }
    

    Then you would define the column to display the name as data: 'name()'.

    So yup - limited use case - but if the function is expected to be callable as a string, then using a closure function would be the way to do it.

    Allan

  • D95D95 Posts: 1Questions: 0Answers: 0

    I have the exact same problem, which infogulch described.

    Now I understand, that it was never intended to do this.
    But if it should do it anyway, some lines worked for me:

    $.fn.dataTable.render.render_Image = function () {
      return function ( data, type, row ) {
        return '<center><img src="/images/viewpic.php?imageID='+data+'"></center>';
      };
    }; 
    
    var columns = [
    ...
                    {
                        "title": "Image",
                        "name": "Image",
                        "data": "Image",
                        "visible": true,
                        "defaultContent": "no Image",
                        "render": "$.fn.dataTable.render.render_Image()"
                    }
                ];
    
    $.each(columns, function( index, value ) {
      if(typeof value.render != 'undefined'){
        value.render = eval(value.render);
      } 
    });
    
      $('#table_id').DataTable({"columns": columns,
    ...
    

    Note, that anything would be evalled, when it is in render.
    May this workaround be useful for someone someday.
    Use it with no warranty.

This discussion has been closed.