We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date

Error when Printing DataGrid

Hello,

I'm trying to use the exportToPdf from the SfDataGrid per this article here: https://help.syncfusion.com/flutter/datagrid/export-to-pdf

Printing functionality only really needs to work with Web (although with iOS and Android is good to have).

The Version I'm using is here:

cupertino_icons: ^1.0.2
firebase_core: ^1.21.1
firebase_auth: ^3.7.0
cloud_firestore: ^3.4.6
syncfusion_flutter_calendar: ^20.2.40
provider: ^6.0.3
syncfusion_flutter_datagrid: ^20.2.50
syncfusion_flutter_datagrid_export: ^20.3.49-beta

The Click event I'm using has the following code:

I have a global key:

final GlobalKey sfDataGridKey = GlobalKey();

And use this with an ElevatedButton.Icon as outlined below:

ElevatedButton.icon(
onPressed: () async {
print('Start Printing');
PdfDocument document = sfDataGridKey.currentState!.exportToPdfDocument();
final List bytes = document.saveSync();

document.dispose();
print('Done Printing');
},
icon: const Icon(Icons.print),
label: const Text('Print'),
),
SfDataGrid(
key: sfDataGridKey,
controller: _dataGridController,
selectionMode: SelectionMode.single,
source: _pendingEventDataSource = PendingEventDataSource(pendingEvents),
columnWidthMode: ColumnWidthMode.fill,
columns: [

The Error I'm seeing below:

Start Printing

Error: Unexpected null value.

dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 266:49 throw_

dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 528:63 nullCheck

packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 583:75 getCellValue

packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 394:32 exportRow

packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 381:7 exportRows

packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 483:5 exportToPdfGrid

packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 415:29 exportToPdfDocument

packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 156:21 DataGridPdfExportExtensions.exportToPdfDocument

packages/prod_scheduler_acc/widgets/data_grid_printing.dart 128:82

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 123:5 _async

packages/prod_scheduler_acc/widgets/data_grid_printing.dart 126:40

packages/flutter/src/material/ink_well.dart 1072:21 handleTap

packages/flutter/src/gestures/recognizer.dart 253:24 invokeCallback

packages/flutter/src/gestures/tap.dart 627:11 handleTapUp

packages/flutter/src/gestures/tap.dart 306:5 [_checkUp]

packages/flutter/src/gestures/tap.dart 239:7 handlePrimaryPointer

packages/flutter/src/gestures/recognizer.dart 615:9 handleEvent

packages/flutter/src/gestures/pointer_router.dart 98:12 [_dispatch]

packages/flutter/src/gestures/pointer_router.dart 143:9

dart-sdk/lib/_internal/js_dev_runtime/private/linked_hash_map.dart 21:13 forEach

packages/flutter/src/gestures/pointer_router.dart 141:17 [_dispatchEventToRoutes]

packages/flutter/src/gestures/pointer_router.dart 127:7 route

packages/flutter/src/gestures/binding.dart 460:19 handleEvent

packages/flutter/src/gestures/binding.dart 440:14 dispatchEvent

packages/flutter/src/rendering/binding.dart 337:11 dispatchEvent

packages/flutter/src/gestures/binding.dart 395:7 [_handlePointerEventImmediately]

packages/flutter/src/gestures/binding.dart 357:5 handlePointerEvent

packages/flutter/src/gestures/binding.dart 314:7 [_flushPointerEventQueue]

packages/flutter/src/gestures/binding.dart 295:7 [_handlePointerDataPacket]

lib/_engine/engine/platform_dispatcher.dart 1183:13 invoke1

lib/_engine/engine/platform_dispatcher.dart 244:5 invokeOnPointerDataPacket

lib/_engine/engine/pointer_binding.dart 147:39 [_onPointerData]

lib/_engine/engine/pointer_binding.dart 653:20

lib/_engine/engine/pointer_binding.dart 594:14

lib/_engine/engine/pointer_binding.dart 288:16 loggedHandler

lib/_engine/engine/pointer_binding.dart 179:80

dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 334:14 _checkAndCall

dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 339:39 dcall


Is there a working version of the export to PDF for the web?


If I use a non-async function call, I get this error:


======== Exception caught by gesture ===============================================================

The following TypeErrorImpl was thrown while handling a gesture:

Unexpected null value.


When the exception was thrown, this was the stack:

dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 266:49 throw_

dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 528:63 nullCheck

packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 583:75 getCellValue

packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 394:32 exportRow

packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 381:7 exportRows

packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 483:5 exportToPdfGrid

packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 415:29 exportToPdfDocument

packages/syncfusion_flutter_datagrid_export/src/export_to_pdf.dart 156:21 DataGridPdfExportExtensions.exportToPdfDocument

packages/prod_scheduler_acc/widgets/data_grid_printing.dart 128:82 <fn>

packages/flutter/src/material/ink_well.dart 1072:21 handleTap

packages/flutter/src/gestures/recognizer.dart 253:24 invokeCallback

packages/flutter/src/gestures/tap.dart 627:11 handleTapUp

packages/flutter/src/gestures/tap.dart 306:5 [_checkUp]

packages/flutter/src/gestures/tap.dart 239:7 handlePrimaryPointer

packages/flutter/src/gestures/recognizer.dart 615:9 handleEvent

packages/flutter/src/gestures/pointer_router.dart 98:12 [_dispatch]

packages/flutter/src/gestures/pointer_router.dart 143:9 <fn>

dart-sdk/lib/_internal/js_dev_runtime/private/linked_hash_map.dart 21:13 forEach

packages/flutter/src/gestures/pointer_router.dart 141:17 [_dispatchEventToRoutes]

packages/flutter/src/gestures/pointer_router.dart 127:7 route

packages/flutter/src/gestures/binding.dart 460:19 handleEvent

packages/flutter/src/gestures/binding.dart 440:14 dispatchEvent

packages/flutter/src/rendering/binding.dart 337:11 dispatchEvent

packages/flutter/src/gestures/binding.dart 395:7 [_handlePointerEventImmediately]

packages/flutter/src/gestures/binding.dart 357:5 handlePointerEvent

packages/flutter/src/gestures/binding.dart 314:7 [_flushPointerEventQueue]

packages/flutter/src/gestures/binding.dart 295:7 [_handlePointerDataPacket]

lib/_engine/engine/platform_dispatcher.dart 1183:13 invoke1

lib/_engine/engine/platform_dispatcher.dart 244:5 invokeOnPointerDataPacket

lib/_engine/engine/pointer_binding.dart 147:39 [_onPointerData]

lib/_engine/engine/pointer_binding.dart 653:20 <fn>

lib/_engine/engine/pointer_binding.dart 594:14 <fn>

lib/_engine/engine/pointer_binding.dart 288:16 loggedHandler

lib/_engine/engine/pointer_binding.dart 179:80 <fn>

dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 334:14 _checkAndCall

dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 339:39 dcall

Handler: "onTap"

Recognizer: TapGestureRecognizer#3ba07

  debugOwner: GestureDetector

  state: possible

  won arena

  finalPosition: Offset(329.5, 119.5)

  finalLocalPosition: Offset(62.5, 6.5)

  button: 1

  sent tap down

====================================================================================================





6 Replies

TP Tamilarasan Paranthaman Syncfusion Team October 12, 2022 11:47 AM UTC

Hi Martin,


Based on the provided information, we are unable to reproduce the reported issue. We have tested the following sample and it’s working fine on our end. We suspect that you’re setting different names for the column in the buildDataGridRow and  GridColumn.columnName. We map the values based on the column name which is set in the buildDataGridRow and GridColumn.columnName. So, you need to set the same name in both places. That's the behavior of DataGrid. We have prepared a simple sample for that. Please check the following code snippet and sample.


 

 @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 =

                  _key.currentState!.exportToPdfDocument();

 

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

              await helper.saveAndLaunchFile(bytes, '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: _key,

                columns: getColumns,

                columnWidthMode: ColumnWidthMode.fill),

          ))

        ]));

  }

}

 

List<GridColumn> get getColumns {

  return <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',

              overflow: TextOverflow.ellipsis,

            ))),

    GridColumn(

        columnName: 'salary',

        label: Container(

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

            alignment: Alignment.center,

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

  ];

}

 

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();

  }

}


Sample Link: https://www.syncfusion.com/downloads/support/directtrac/general/ze/sample-426386132


We hope this helps. Please let us know if you need any further assistance with this.


Regards,

Tamilarasan



MA Martin October 12, 2022 02:03 PM UTC

Thank you Tamilarasan,

The Datagrid is working very well, it's only the export to PDF that is not working. I've included the dataSource code below as well as the Grid code from the DataGrid itself. 


One thing that I do not have currently is the "HELPER" methods that you are referencing in the code sample as well as the "HELPER" function call in my onclick event. The helper function looks like it works for EXCEL files but perhaps I'm reading it incorrectly.

This is the line of code that you have that I'm referring it - I do not have this in my call: 

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

This seems to call this function:

// ignore_for_file: avoid_web_libraries_in_flutter

import 'dart:async';

import 'dart:convert';

import 'dart:html';

///To save the excel sheet in the web platform.

Future<void> saveAndLaunchFile(List<int> bytes, String fileName) async {

  AnchorElement(

      rel='nofollow' href:

          'data:application/octet-stream;charset=utf-16le;base64,${base64.encode(bytes)}')

    ..setAttribute('download', fileName)

    ..click();

}

Below is my datasource and my grid columns:

class PendingEventDataSource extends DataGridSource {
/// CTOR
/// This takes a List collection of ScheduleEvents that are marked as 'Pending'
PendingEventDataSource(List<SchedulerEvent> pendingEvents) {
dataGridRows = pendingEvents.map<DataGridRow>(
(inputPendingEvent) {
return DataGridRow(
cells: [
/// map the columns to the value as each row is built
DataGridCell(columnName: 'Requested Location', value: inputPendingEvent.cemeteryLocation),
DataGridCell(columnName: 'fname', value: inputPendingEvent.fname),
DataGridCell(columnName: 'lname', value: inputPendingEvent.lname),
DataGridCell(columnName: 'created', value: DateFormat(kQptDisplayDateTimeFormatUS).format(inputPendingEvent.createdDate!)),
],
);
},
).toList();
}

/// these will be tied to the rows from the Pending Events
late List<DataGridRow> dataGridRows;

/// override the rows property and assign a field to it
/// the dataGridRows was declared just above this call
/// Fetches the rows available for data population.
/// Also, it is used to fetch the corresponding data object to process the selection.
@override
List<DataGridRow> get rows => dataGridRows;

/// This defines the widget to build for each cell of data as the Rows are built
/// row.getCells is the main method
/// Map each cell with a "widget" and pass a function that returns a Container (or whatever)
/// Fetches the widget for each cell with DataGridRowAdapter
@override
DataGridRowAdapter? buildRow(DataGridRow row) {
return DataGridRowAdapter(
color: kQptColorLightGrey200,
cells: row.getCells().map<Widget>((inputPendingEventCellData) {
return Container(
alignment: Alignment.center,
child: Center(
child: FittedBox(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
inputPendingEventCellData.value.toString(),
),
),
)),
);
}).toList());
}
}

Columns:

SfDataGrid(
key: sfDataGridKey,
controller: _dataGridController,
selectionMode: SelectionMode.single,
source: _pendingEventDataSource = PendingEventDataSource(pendingEvents),
columnWidthMode: ColumnWidthMode.fill,
columns: [
GridColumn(
columnName: 'Requested Location',
label: Container(
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: const Text(
'Requested Location',
style: TextStyle(color: Colors.white),
),
),
),
GridColumn(
columnName: 'fname',
label: Container(
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: const Text(
'First Name',
style: TextStyle(color: Colors.white),
),
),
),
GridColumn(
columnName: 'lname',
label: Container(
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: const Text(
'Last Name',
style: TextStyle(color: Colors.white),
),
),
),
GridColumn(
columnName: 'created',
label: Container(
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: const Text(
'Created',
style: TextStyle(color: Colors.white),
),
),
),
],


MA Martin October 12, 2022 03:34 PM UTC

Tamilarasan,

Thanks for your help - is there a way to not download the file? 

Meaning is it possible to simply open the PDF document and then take an action like print?



TP Tamilarasan Paranthaman Syncfusion Team October 13, 2022 01:21 PM UTC

Hi Martin,


As per your requirement, you can achieve it on the Web platform using the html.dart package. We have prepared a sample for that. In that sample, you can export the DataGrid content with a button click. It directly loads the PDF document in the new window without downloading it. You can now print or download the document after exporting it. Please check the following sample and code snippet.


import 'dart:html' as html;

 

  @override

  void initState() {

    super.initState();

    employees = getEmployeeData();

    _employeeDataSource = EmployeeDataSource(employees);

  }

 

  @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 =

                  _key.currentState!.exportToPdfDocument();

 

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

              Uint8List bytes = Uint8List.fromList(data);

 

              final url = html.Url.createObjectUrl(

                  html.Blob([bytes], 'application/pdf'));

              html.window.open(url, '_blank');

 

              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: _key,

                columns: getColumns,

                columnWidthMode: ColumnWidthMode.fill),

          ))

        ]));

  }

}



Sample: https://www.syncfusion.com/downloads/support/directtrac/general/ze/sample-154064527


We hope this helps. Please let us know if you need any further assistance.


Regards,

Tamilarasan


If this response is helpful, please consider Accepting it as the solution so that other members can locate it more quickly.



MA Martin October 14, 2022 03:37 AM UTC

Tamilarasan Thank you!

That works very well.

I'll need to conditionally load dart:html as this will ultimately need to work for iOS, Android and Web - but I'll dig into how to do that (new to Flutter).


Have a good weekend!

--



TP Tamilarasan Paranthaman Syncfusion Team October 14, 2022 12:42 PM UTC

Hi Martin,


We are glad that the provided response meets your requirement. Please let us know if you require further assistance. As always, we are happy to help you out.


Regards,

Tamilarasan


Loader.
Live Chat Icon For mobile
Up arrow icon