Data grid export Error Unexpected null value

Hi friends,

I'm trying to export data to PDF, but I get a strange error: Error: Unexpected null value like below:

KEY: SfDataGrid-[LabeledGlobalKey#14323](dependencies: [Directionality, MediaQuery, _InheritedTheme, _LocalizationsScope-[GlobalKey#0478f]], state: SfDataGridState#fcd97(ticker inactive))
EXPORTING DATA NOW!
DATA: SfDataGridState#fcd97(ticker inactive)
Error: Unexpected null value.
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 294:49 throw_
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 855:63 nullCheck
packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 587:75 getCellValue
packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 398:32 exportRow
packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 385:7 exportRows
packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 487:5 exportToPdfGrid
packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 419:29 exportToPdfDocument
packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 158:21 DataGridPdfExportExtensions.exportToPdfDocument
packages/b2bboostify/apis/b2bbHelper.dart 17:60 exportDataGridToPdf
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 84:54 runBody
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 127:5 _async
packages/b2bboostify/apis/b2bbHelper.dart 9:42 exportDataGridToPdf
packages/flutter/src/material/ink_well.dart 1154:21 handleTap


My function:

import 'package:syncfusion_flutter_xlsio/xlsio.dart' hide Column, Row, Border;
import 'package:myproj/utils/save_file_web.dart' as webhelper;
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:syncfusion_flutter_datagrid_export/export.dart';
import 'package:syncfusion_flutter_pdf/pdf.dart';
import 'package:flutter/material.dart';

class B2BBHelper {
static Future<void> exportDataGridToPdf(
GlobalKey<SfDataGridState> dataGridKey) async {
print('EXPORTING DATA NOW!');
//final ByteData data = await rootBundle.load('assets/images/logo_small.png');
var dataaa = dataGridKey.currentState!.toString();

print('DATA: $dataaa');

final PdfDocument document = dataGridKey.currentState!.exportToPdfDocument(
fitAllColumnsInOnePage: true,
cellExport: (DataGridCellPdfExportDetails details) {
if (details.cellType == DataGridExportCellType.row) {
// if (details.columnName == 'Shipped Date') {
// details.pdfCell.value = DateFormat('MM/dd/yyyy')
// .format(DateTime.parse(details.pdfCell.value));
// }
}
},
headerFooterExport: (DataGridPdfHeaderFooterExportDetails details) {
final double width = details.pdfPage.getClientSize().width;
final PdfPageTemplateElement header =
PdfPageTemplateElement(Rect.fromLTWH(0, 0, width, 65));

// header.graphics.drawImage(
// PdfBitmap(data.buffer
// .asUint8List(data.offsetInBytes, data.lengthInBytes)),
// Rect.fromLTWH(width - 60, 0, 60, 60));

header.graphics.drawString(
'Companies Details',
PdfStandardFont(PdfFontFamily.helvetica, 13,
style: PdfFontStyle.bold),
bounds: const Rect.fromLTWH(0, 25, 200, 60),
);

details.pdfDocumentTemplate.top = header;
});
final List<int> bytes = document.saveSync();
await webhelper.FileSaveHelper.saveAndLaunchFile(
bytes, 'MyFile_NewCompanies.pdf');
document.dispose();
}
}


What can cause this error :( ? Please help me any suggestion will be much appreciated!
Thanks in advance!


6 Replies 1 reply marked as answer

TP Tamilarasan Paranthaman Syncfusion Team November 9, 2023 01:17 PM UTC

Hi Dorin Buraca,

Based on the provided information and call stack details, it seems that this issue might be arising due to a mismatch in the column names between `GridColumn.columnName` and `DataGridCell.columnName`. In our source, we retrieve values from the cell based on the column name specified in both `GridColumn.columnName` and `DataGridCell.columnName`. We have conducted testing with a simple sample using the latest version of the package, and it is functioning correctly on our end.


We kindly request you to verify that the column names are consistent between `GridColumn.columnName` and `DataGridCell.columnName` in your sample.


For your convenience, we have provided a simple sample that we extensively tested on our end. Please review the following code snippet and the attached sample for more comprehensive information.


In GridColumn:



 @override

  Widget build(BuildContext context) {

    return Scaffold(

        appBar: AppBar(title: const Text('SfDatagrid Demo')),

        body: Column(children: [

          const Padding(padding: EdgeInsets.only(top: 30)),

          SizedBox(

              child: ElevatedButton.icon(

            onPressed: () async {

              final PdfDocument document =

                  dataGridKey.currentState!.exportToPdfDocument(

                fitAllColumnsInOnePage: true,

              );

              final List<int> data = document.saveSync();

              await helper.saveAndLaunchFile(data, 'DataGrid.pdf');

              document.dispose();

            },

            icon: const Icon(Icons.print),

            label: const Text('Export DataGrid to PDF'),

          )),

          Expanded(

              child: Card(

            margin: const EdgeInsets.all(30),

            child: SfDataGrid(

              source: _employeeDataSource,

              key: dataGridKey,

              columns: <GridColumn>[

                GridColumn(

                    columnName: 'id',

                    label: Container(

                        padding: const EdgeInsets.symmetric(horizontal: 16.0),

                        alignment: Alignment.center,

                        child: const Text(

                          'ID',

                        ))),

                GridColumn(

                    columnName: 'name',

                    label: Container(

                        padding: const EdgeInsets.symmetric(horizontal: 16.0),

                        alignment: Alignment.center,

                        child: const Text('Name'))),

                GridColumn(

                    columnName: 'designation',

                    label: Container(

                        padding: const EdgeInsets.symmetric(horizontal: 16.0),

                        alignment: Alignment.center,

                        child: const Text('Designation'))),

                GridColumn(

                    columnName: 'salary',

                    label: Container(

                        padding: const EdgeInsets.symmetric(horizontal: 16.0),

                        alignment: Alignment.center,

                        child: const Text('Salary'))),

              ],

              columnWidthMode: ColumnWidthMode.fill,

            ),

          ))

        ]));

  }

}

In DataGridSource:

class EmployeeDataSource extends DataGridSource {

  EmployeeDataSource(List<Employee> employees) {

    buildDataGridRow(employees);

  }


  void buildDataGridRow(List<Employee> employeeData) {

    dataGridRow = employeeData.map<DataGridRow>((employee) {

      return DataGridRow(cells: [

        DataGridCell<int>(columnName: 'id', value: employee.id),

        DataGridCell<String>(columnName: 'name', value: employee.name),

        DataGridCell<String>(

            columnName: 'designation', value: employee.designation),

        DataGridCell<int>(columnName: 'salary', value: employee.salary),

      ]);

    }).toList();

  }

}


​Regards,

Tamilarasan


Attachment: Sample_464372fd.zip


DO Dorin November 9, 2023 08:25 PM UTC

Hi Tamilarasan,

Thanks for your quick reply, was very helpful to me, I found the bug in my case. 
What I'm wondering now is how can I redefine the Column name for the exported document, because by default I get the value from the  GridColumn.columnName ​... but my first concern is how can I export only the selected items from the list, not the entire one?

This is a major option for me :(


Thanks in advance!​



TP Tamilarasan Paranthaman Syncfusion Team November 10, 2023 12:45 PM UTC

Dorin Buraca,


Regarding: how can I redefine the Column name for the exported document.

To customize the cell value during PDF export, you can directly set the cell value in the PdfGrid using the PdfCell property available in the argument of the cellExport callback. For more detailed information, please refer to the following code snippet.


  @override

  Widget build(BuildContext context) {

    return Scaffold(

        appBar: AppBar(title: const Text('SfDatagrid Demo')),

        body: Column(children: [

          const Padding(padding: EdgeInsets.only(top: 30)),

          SizedBox(

              child: ElevatedButton.icon(

            onPressed: () async {

              final PdfDocument document =

                  dataGridKey.currentState!.exportToPdfDocument(

                fitAllColumnsInOnePage: true,

                cellExport: (details) {

                  if (details.cellType == DataGridExportCellType.columnHeader) {

                    if (details.cellValue == 'id') {

                      details.pdfCell.value = 'Employee ID';

                    } else if (details.cellValue == 'name') {

                      details.pdfCell.value = 'Employee Name';

                    } else if (details.cellValue == 'designation') {

                      details.pdfCell.value = 'Employee Designation';

                    } else if (details.cellValue == 'salary') {

                      details.pdfCell.value = 'Employee Salary';

                    }

                  }

                },

              );

              final List<int> data = document.saveSync();

              await helper.saveAndLaunchFile(data, 'DataGrid.pdf');

              document.dispose();

            },

            icon: const Icon(Icons.print),

            label: const Text('Export DataGrid to PDF'),

          )),

          Expanded(

              child: Card(

            margin: const EdgeInsets.all(30),

            child: SfDataGrid(

              source: _employeeDataSource,

              controller: dataGridController,

              selectionMode: SelectionMode.multiple,

              key: dataGridKey,

              columns: getColumns,

              columnWidthMode: ColumnWidthMode.fill,

            ),

          ))

        ]));

  }


Regarding: how can I export only the selected items from the list, not the entire one?

To export selected items in the DataGrid, utilize the rows parameter in exportToPdfDocument and exportToPdfGrid methods. Pass the selected rows from DataGridController.selectedRows to the rows parameter to export only the selected rows. For further guidance, please refer to the following code snippet.


@override

  Widget build(BuildContext context) {

    return Scaffold(

        appBar: AppBar(title: const Text('SfDatagrid Demo')),

        body: Column(children: [

          const Padding(padding: EdgeInsets.only(top: 30)),

          SizedBox(

              child: ElevatedButton.icon(

            onPressed: () async {

              final PdfDocument document =

                  dataGridKey.currentState!.exportToPdfDocument(

                fitAllColumnsInOnePage: true,

                rows: dataGridController.selectedRows,

              );

              final List<int> data = document.saveSync();

              await helper.saveAndLaunchFile(data, 'DataGrid.pdf');

              document.dispose();

            },

            icon: const Icon(Icons.print),

            label: const Text('Export DataGrid Selected Rows to PDF'),

          )),

          Expanded(

              child: Card(

            margin: const EdgeInsets.all(30),

            child: SfDataGrid(

              source: _employeeDataSource,

              controller: dataGridController,

              selectionMode: SelectionMode.multiple,

              key: dataGridKey,

              columns: getColumns,

              columnWidthMode: ColumnWidthMode.fill,

            ),

          ))

        ]));

  }


We have also provided a simple sample for your reference, demonstrating how to export selected items and customize the header text during the export process. Check the attached sample for more information.


Attachment: Sample_80912740.zip


DO Dorin November 10, 2023 06:46 PM UTC

Hi Tamilarasan,

Thanks a lot for your great support, I managed to make them work!

One question, how can I define the Headers titles like in Pdf Export, as well for Excel Export?

if (details.cellType == DataGridExportCellType.columnHeader) {

if (details.cellValue == 'id') {

details.pdfCell.value = 'Employee ID';

} else if (details.cellValue == 'name') {

details.pdfCell.value = 'Employee Name';

} else if (details.cellValue == 'designation') {

details.pdfCell.value = 'Employee Designation';

} else if (details.cellValue == 'salary') {

details.pdfCell.value = 'Employee Salary';

}

}

},


2. Is there a possibility to modify the cell data for excel export?

Thanks in advance!



NY Nirmalkumar Yuvaraj Syncfusion Team November 13, 2023 06:41 AM UTC

Hi Dorin,


By default, the DataGrid supports cell customization for both Excel and PDF while exporting. Please refer to the User Guide (UG) document to learn more about these features.


Export to Excel - https://help.syncfusion.com/flutter/datagrid/export-to-excel#customize-cell-values-while-exporting

Export to PDF - https://help.syncfusion.com/flutter/datagrid/export-to-pdf#customize-cell-values-while-exporting


If this information is helpful, kindly consider accepting it as the solution so that other members can locate it more quickly.


Regards,

Nirmalkumar.



DO Dorin November 13, 2023 01:19 PM UTC

Hi Nirmalkumar,

Thanks for your reply, the solution for custom headers in excel is:

          if (details.cellType == DataGridExportCellType.columnHeader &&
              details.columnName == 'companyName') {
            details.excelRange.value = 'Lead';
          }


Thanks!


Marked as answer
Loader.
Up arrow icon