angularjs - Ng-grid export that calls cell filters

I'm working with an ng-grid and some columns have filters applied. However, when I export to CSV right now the values are displayed without filters: a record might like like this in json:

{"service_date":"2014-02-10T00:00:00.000Z",
 "service_code":"someJob3",
 "price":1234.56}

but in the grid it is displayed as:

Service Date |Service Desc | Price
-------------------------------------
Feb 10,2014  |Some Job 3   | $1,234.56

I'd like when I get an extract for it to appear as if the filter are applied but the only csv plugin does not seem to call cell filters, and simply returns the values in raw form. How can I invoke the filters?

4 Answers

  1. Randolph- Reply

    2019-11-13

    I discovered a solution that works with ui-grid (the replacement version of ng-grid), and it's much simpler than the plugin workaround that Matt Welch had to develop for ng-grid 2.0.

    You can specify an exporterFieldCallback in your gridOptions and then do whatever you want based on the col.name. For my use case I had user IDs, which I needed to cross reference to an array index. I'd built a cellFilter for the table, but it obviously wasn't reflected in the exported CSV until I added the exporterFieldCallback like so:

    $scope.gridOptions = {
        ...
    
        exporterFieldCallback: function( grid, row, col, input ) {
            if( col.name == 'account_executive_id' || col.name == 'account_manager_id' ) {
                return adminUsers.getUserName(input);
            } else {
                return input;
            }
        },
        ...
    }
    

    The callback requires the grid, row, col, and input variables, and then you can do anything inside it to return whatever values you need exported. It would be nice if there were a "use what's displayed in the grid" flag, but this is still a pretty simple solution, even if it appears to be undocumented.

  2. Randy- Reply

    2019-11-13

    I know this question is a few months old but I was searching for the same thing and figured I'd document how I solved the problem.

    Side note: I saw that there is an ng-grid-wysiwyg-export.js plugin in the plugins folder but I found no examples or documentation on it's use and didn't take the time to figure it out because...

    I did find that there is a playground.html file in the ng-grid plugins folder that has an example for the CSV plugin. It demonstrated how to use the columnOverrides feature that you can pass into the plugin constructor via the opts parameter:

    $scope.myData = [ 
        {hasThing: false,  obj: {a:5, b:6}, name: "Moroni", age: 50, ln: 'sdf'},
        {hasThing:  true,  obj: {a:6, b:7}, ln: "Tiasdfsdfnd", age: 43}
    ];
    
    var csvOpts = { columnOverrides: { obj: function(o) { return o.a + '|' +  o.b; } } };
    
    $scope.gridOptionsBig = {
        data: 'myData',
        plugins: [new ngGridCsvExportPlugin(csvOpts)],
        showFooter: true
    };
    

    So for the example in the question above, you can define override functions for each column that you want to apply filters on, like so:

    var csvOpts = { 
        columnOverrides: {
            service_date: function(d) { return $filter('date')(d); },
            service_code: function(c) { return $filter('myCustomCamelCaseFilter')(c); },
            price: function(p) { return $filter('currency')(p); }
        }
    };
    

    While it's a little extra work to have to define these instead of just invoking the already-defined cellFilter from the columnDefs, this approach DOES give you the flexibility to have your exported data be slightly different than what is displayed on the screen... perhaps a more expressive date format, etc.

  3. kate- Reply

    2019-11-13

    I developed for this a solution based on the exporterFieldCallback.

    My idea is to DO NOT REPEAT the filter expression you already have in the columnDefs, like:

      {
        field: 'totalFileSize',
        headerCellClass: $scope.highlightFilteredHeader,
        cellFilter: "notAvailable:'N/A' | readableFileSize",
        displayName: "Total size",
        cellClass:"rightcell"
      },
    

    where, of course, notAvailable and readableFileSize are both custom filters defined by me and regularly used by the ui-grid.

    exporterFieldCallback: function( grid, row, col, input ) {
      if (col.cellFilter!=undefined && col.cellFilter.length !=0) {
        var filters = col.cellFilter.split('|');
        for(i =0; i<filters.length;i++) {
          var pars = filters[i].match(/[^\:"']+|'([^']*)'|'([^']*)'+/g);
          var filterName= pars[0].trim();
          var filterPar = null;
          if (pars.length ==2) {
             filterPar = pars[1].slice(1, -1);
            input = $filter(filterName)( input,filterPar);
          } else {
            input = $filter(filterName)( input );
          }
        }
      }
      return input;
    
    }
    

    It's poor because I'm a Javascript dummy, it works only for filters that accepts no parameter or one parameter; but can be for sure improved, I was on the rush. Also in the regex most probably there is some redundance

    It takes the cellFilter if defined for the column and programmatically apply again as well. With this single generic function I added export to ALL the columns of all the ui-grids.

  4. Aaron- Reply

    2019-11-13

    Based on the response from 'angelodelia'. Here is my modifed version. This would work for multiple filter with multiple parameters.

     exporterFieldCallback: function (grid, row, col, input) {
                if (col.cellFilter) { // check if any filter is applied on the column
                    var filters = col.cellFilter.split('|'); // get all the filters applied
                    angular.forEach(filters, function (filter) {
                        var filterName = filter.split(':')[0]; // fetch filter name
                        var filterParams = filter.split(':').splice(1); //fetch all the filter parameters
                        filterParams.unshift(input); // insert the input element to the filter parameters list
                        var filterFn = $filter(filterName); // filter function
                        // call the filter, with multiple filter parameters. 
                        //'Apply' will call the function and pass the array elements as individual parameters to that function.
                        input = filterFn.apply(this, filterParams); 
                    })
                    return input;
                }
                else
                    return input;
            }
    

    This generic function will help export the data as it is displayed in UI Grid (after applying the filters.)

Leave a Reply

Your email address will not be published. Required fields are marked *

You can use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>