syncfusion / flutter-widgets

Syncfusion Flutter widgets libraries include high quality UI widgets and file-format packages to help you create rich, high-quality applications for iOS, Android, and web from a single code base.
1.46k stars 680 forks source link

Grid Add Remove Row Add Row and Save Rows Issues #585

Closed abdulrehmananwar closed 1 year ago

abdulrehmananwar commented 2 years ago

List of Issue:- 1- Header Border not showing on top and left side. 2- on long press i have create function to remove row which is not removing row. 3- when i press save button all rows have to clear and grid should be reset. button showing issue on 4th step. 4- after pressing save button i press add button which added new row button some time focus remain on last row cell i cant to reset focus . my code is as below

import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart';

void main() { runApp(MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: SfDataGridDemo(title: 'Syncfusion SfDataGrid'))); }

class SfDataGridDemo extends StatefulWidget { SfDataGridDemo({Key? key, required this.title}) : super(key: key);

final String title;

@override _SfDataGridDemoState createState() => _SfDataGridDemoState(); }

class CustomSelectionManager extends RowSelectionManager { CustomSelectionManager(this.controller);

DataGridController controller;

@override void handleKeyEvent(RawKeyEvent keyEvent) { if (keyEvent.logicalKey == LogicalKeyboardKey.tab) { super.handleKeyEvent(keyEvent); controller.beginEdit(controller.currentCell); return; } super.handleKeyEvent(keyEvent); } }

class _SfDataGridDemoState extends State {

void _showPopup(BuildContext context,int index,Offset position) async { //get the render box from the context final RenderBox renderBox = context.findRenderObject() as RenderBox; //get the global position, from the widget local position // final offset = renderBox.localToGlobal(Offset.zero);

//*calculate the start point in this case, below the button
final left = position.dx;
final top = position.dy;

// + renderBox.size.height; //*The right does not indicates the width final right = left + renderBox.size.width; const Map<String, IconData> _options = { 'Remove Row' : Icons.remove_circle, };

//*show the menu
final value = await showMenu<String>(
  // color: Colors.red,
  /*
    shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(20.0)
    ),

   */
    context: context,
    //position: position.dx,

// position: RelativeRect.fromLTRB(left, top, right, 0.0), items: _options.entries.map<PopupMenuEntry>((entry) { return PopupMenuItem( value: entry.key, child: SizedBox( // width: 200, //*width of popup child: Row( children: [ Icon(entry.value, color: Colors.redAccent), const SizedBox(width: 10.0), Text(entry.key) ], ), ), onTap: (){ if (entry.key == "Remove Row") { _employees.removeAt(index-1); dataGridRows.removeAt(index-1); _dataGridController.notifyListeners();

          }

        },
      );
    }).toList()
);

// print(value); }

late EmployeeDataSource _employeeDataSource; List _employees = []; List dataGridRows = [];

late DataGridController _dataGridController; late CustomSelectionManager _customSelectionManager;

@override void initState() { super.initState(); _employees = getEmployeeData(); _employeeDataSource = EmployeeDataSource(_employees,dataGridRows); _dataGridController = DataGridController(); _customSelectionManager = CustomSelectionManager(_dataGridController); }

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('SfDataGrid Editing'), ), body: Column( children: [ Row(children: [ ElevatedButton( onPressed: () { FocusScope.of(context).notifyListeners(); _employees.add(Employee(0, '', '', 0)); _employeeDataSource = EmployeeDataSource(_employees,dataGridRows); _employeeDataSource.notifyListeners();

            },
            child: Text('add new row')),
        ElevatedButton(
            onPressed: () {
              FocusScope.of(context).notifyListeners();
              _employees.clear();
              dataGridRows.clear();
              _employeeDataSource = EmployeeDataSource(_employees,dataGridRows);
              _employeeDataSource.notifyListeners();

            },
            child: Text('Save')),
      ],),
      Expanded(
        child: SfDataGrid(
          source: _employeeDataSource,
          allowEditing: true,
          controller: _dataGridController,
          selectionMode: SelectionMode.single,
          onCellLongPress: (DataGridCellLongPressDetails  details) async{
_showPopup(context,details.rowColumnIndex.rowIndex,details.globalPosition);
;},
          headerGridLinesVisibility: GridLinesVisibility.both,
          gridLinesVisibility: GridLinesVisibility.both,
          navigationMode: GridNavigationMode.cell,

// columnWidthMode: ColumnWidthMode.fill, selectionManager: _customSelectionManager, editingGestureType: EditingGestureType.tap, columns: [ GridColumn( columnName: 'id', label: Container( padding: EdgeInsets.symmetric(horizontal: 16.0), alignment: Alignment.centerRight, child: Text( 'ID', overflow: TextOverflow.ellipsis, ), ), ), GridColumn( columnName: 'name', label: Container( padding: EdgeInsets.symmetric(horizontal: 16.0), alignment: Alignment.centerLeft, child: Text( 'Name', overflow: TextOverflow.ellipsis, ), ), ), GridColumn( columnName: 'designation', label: Container( padding: EdgeInsets.symmetric(horizontal: 16.0), alignment: Alignment.centerLeft, child: Text( 'Designation', overflow: TextOverflow.ellipsis, ), ), ), GridColumn( columnName: 'salary', label: Container( padding: EdgeInsets.symmetric(horizontal: 16.0), alignment: Alignment.centerRight, child: Text( 'Salary', overflow: TextOverflow.ellipsis, ), ), ), ], ), ),

    ],
  ),
);

}

List getEmployeeData() { return [ Employee(10010, 'Grimes', 'Developer', 15000) ]; } }

class EmployeeDataSource extends DataGridSource { EmployeeDataSource(this._employees,this.dataGridRows) { dataGridRows = _employees .map((dataGridRow) => dataGridRow.getDataGridRow()) .toList(); }

List _employees = [];

List dataGridRows = [];

/// Helps to hold the new value of all editable widget. /// Based on the new value we will commit the new value into the corresponding /// [DataGridCell] on [onSubmitCell] method. dynamic newCellValue;

/// Help to control the editable text in [TextField] widget. TextEditingController editingController = TextEditingController();

@override List get rows => dataGridRows;

@override DataGridRowAdapter? buildRow(DataGridRow row) { return DataGridRowAdapter( cells: row.getCells().map((dataGridCell) { return Container( alignment: (dataGridCell.columnName == 'id' || dataGridCell.columnName == 'salary') ? Alignment.centerRight : Alignment.centerLeft, padding: EdgeInsets.symmetric(horizontal: 16.0), child: Text( dataGridCell.value.toString(), overflow: TextOverflow.ellipsis, )); }).toList()); }

@override void onCellSubmit(DataGridRow dataGridRow, RowColumnIndex rowColumnIndex, GridColumn column) { final dynamic oldValue = dataGridRow .getCells() .firstWhereOrNull((DataGridCell dataGridCell) => dataGridCell.columnName == column.columnName) ?.value ?? '';

final int dataRowIndex = dataGridRows.indexOf(dataGridRow);

if (newCellValue == null || oldValue == newCellValue) {
  return;
}

if (column.columnName == 'id') {
  dataGridRows[dataRowIndex].getCells()[rowColumnIndex.columnIndex] =
      DataGridCell<int>(columnName: 'id', value: newCellValue);
  _employees[dataRowIndex].id = newCellValue as int;
} else if (column.columnName == 'name') {
  dataGridRows[dataRowIndex].getCells()[rowColumnIndex.columnIndex] =
      DataGridCell<String>(columnName: 'name', value: newCellValue);
  _employees[dataRowIndex].name = newCellValue.toString();
} else if (column.columnName == 'designation') {
  dataGridRows[dataRowIndex].getCells()[rowColumnIndex.columnIndex] =
      DataGridCell<String>(columnName: 'designation', value: newCellValue);
  _employees[dataRowIndex].designation = newCellValue.toString();
} else {
  dataGridRows[dataRowIndex].getCells()[rowColumnIndex.columnIndex] =
      DataGridCell<int>(columnName: 'salary', value: newCellValue);
  _employees[dataRowIndex].salary = newCellValue as int;
}

}

@override bool canSubmitCell(DataGridRow dataGridRow, RowColumnIndex rowColumnIndex, GridColumn column) { // Return false, to retain in edit mode. return true; // or super.canSubmitCell(dataGridRow, rowColumnIndex, column); }

@override Widget? buildEditWidget(DataGridRow dataGridRow, RowColumnIndex rowColumnIndex, GridColumn column, CellSubmit submitCell) { // Text going to display on editable widget final String displayText = dataGridRow .getCells() .firstWhereOrNull((DataGridCell dataGridCell) => dataGridCell.columnName == column.columnName) ?.value ?.toString() ?? '';

// The new cell value must be reset.
// To avoid committing the [DataGridCell] value that was previously edited
// into the current non-modified [DataGridCell].
newCellValue = null;

final bool isNumericType =
    column.columnName == 'id' || column.columnName == 'salary';

// Holds regular expression pattern based on the column type.
final RegExp regExp = _getRegExp(isNumericType, column.columnName);

return Container(
  padding: const EdgeInsets.all(8.0),
  alignment: isNumericType ? Alignment.centerRight : Alignment.centerLeft,
  child: TextField(
    autofocus: true,
    controller: editingController..text = displayText,
    textAlign: isNumericType ? TextAlign.right : TextAlign.left,
    autocorrect: false,
    decoration: InputDecoration(
      contentPadding: const EdgeInsets.fromLTRB(0, 0, 0, 16.0),
    ),
    inputFormatters: <TextInputFormatter>[
      FilteringTextInputFormatter.allow(regExp)
    ],
    keyboardType: isNumericType ? TextInputType.number : TextInputType.text,
    onChanged: (String value) {
      if (value.isNotEmpty) {
        if (isNumericType) {
          newCellValue = int.parse(value);
        } else {
          newCellValue = value;
        }
      } else {
        newCellValue = null;
      }
    },
    onSubmitted: (String value) {
      /// Call [CellSubmit] callback to fire the canSubmitCell and
      /// onCellSubmit to commit the new value in single place.
      submitCell();
    },
  ),
);

}

RegExp _getRegExp(bool isNumericKeyBoard, String columnName) { return isNumericKeyBoard ? RegExp('[0-9]') : RegExp('[a-zA-Z ]'); } }

class Employee { Employee(this.id, this.name, this.designation, this.salary);

int id; String name; String designation; int salary;

DataGridRow getDataGridRow() { return DataGridRow(cells: [ DataGridCell(columnName: 'id', value: id), DataGridCell(columnName: 'name', value: name), DataGridCell(columnName: 'designation', value: designation), DataGridCell(columnName: 'salary', value: salary), ]); } }

Tamilarasan-Paranthaman commented 2 years ago

Hi @abdulrehmananwar,

In the DataGrid source, we didn’t set the top and left border. But you can set it by the sample level itself by using a container with the box decoration. In the second requirement, you need to remove the rows from the _employeeDataSource collection instead of removing them from the local dataGridRow alone. In the third one, you need to call the end edit from the controller when pressing the save button. We have prepared a sample as per your requirements. Please check the following sample code snippet.

Code Snippet:

In Button Click:

ElevatedButton(
onPressed: () {
FocusScope.of(context).notifyListeners();
_employees.add(Employee(0, '', '', 0));
_employeeDataSource =
EmployeeDataSource(_employees, dataGridRows);
_employeeDataSource.updateDataGridSource();
},
child: const Text('add new row')),
ElevatedButton(
onPressed: () {
FocusScope.of(context).notifyListeners();
_dataGridController.endEdit();
_employees.clear();
_employeeDataSource.dataGridRows.clear();
_employeeDataSource =
EmployeeDataSource(_employees, dataGridRows);
_employeeDataSource.updateDataGridSource();
},

In Long Press PopupMenuItem:

final value = await showMenu<dynamic>(
        context: context,
        position: RelativeRect.fromLTRB(left, top, right, 0.0),
        items: _options.entries.map<PopupMenuEntry>((entry) {
          return PopupMenuItem(
            value: entry.key,
            child: SizedBox(
              child: Row(
                children: [
                  Icon(entry.value, color: Colors.redAccent),
                  const SizedBox(width: 10.0),
                  Text(entry.key)
                ],
              ),
            ),
            onTap: () {
              if (entry.key == "Remove Row") {
                _employees.removeAt(index - 1);
                _employeeDataSource.dataGridRows.removeAt(index - 1);
                _employeeDataSource.updateDataGridSource();
              }
            },
          );
        }).toList());

Sample Link: https://www.syncfusion.com/downloads/support/directtrac/general/ze/main1837050188

We hope this helps. If we misunderstood anything, please modify the above sample based on your requirements. It will be helpful for us to check on it and provide you with the solution at the earliest

Regards, Tamilarasan P

abdulrehmananwar commented 2 years ago

How to clear selected cell focus on button click

Tamilarasan-Paranthaman commented 2 years ago

Hi @abdulrehmananwar ,

We are unclear about your requirement. Do you want to exit cell edit mode, move the focus to the out of DataGrid, or remove the navigation cell focus? Can you please provide more details about your requirement with a screenshot of the reference images? so that we could proceed further to provide a better solution.

Regards, Tamilarasan

abdulrehmananwar commented 2 years ago

image this image show foucus on two cells. fist i remove that row where cell focused. when i add new row then focus again showing in that cell i want to clear the focus. i am using TextField in all cells which show in editmode. 1st issue is focus which describe above 2nd issue is some time when i add and remove rows multiple times. when i try to add value some time single cell disabled and i unable to input in that cell. it happend some time dont know why

abdulrehmananwar commented 2 years ago

image

one more issue when i input extra text in cell textfield below scroll bar showing. why its showing against textfield

Tamilarasan-Paranthaman commented 2 years ago

Hi @abdulrehmananwar,

We are currently analyzing the reported issue. We will validate and update further details on February 21, 2021. We appreciate your patience until then.

Regards, Tamilarasan

RenugaSadagoban98 commented 2 years ago

Hi,

Find the following details,


Reported Issue | Response -- | -- **Removed a row where the cell focused. And I added a new row then the focus is again showing in that cell. I want to clear the focus. Sometimes when I add and remove rows multiple times. when I try to add value sometimes a single cell is disabled, and I am unable to input in that cell**. | Based on the provided information, we have checked your reported scenario. but we could not reproduce the reported issues (first and second). We have tested the following sample,https://www.syncfusion.com/downloads/support/directtrac/general/ze/main1837050188Please check the above sample and get back to us if you are still facing the same issue. If yes, please provide the following details,  **Syncfusion updated version,   Issue reproducing video.** It will be helpful for us to check on it and provide you with the solution at the earliest Scrollbar is shown when the text is long while editing the cell | We are analyzing this issue. We will validate and update you with the details in two business days, i.e February 23,2022. We appreciate your patience until then.


Regards,

Renugadevi.

abdulrehmananwar commented 2 years ago

Step 1 add two rows and select last row any cell in editing mode then remove that focused cell row . Step 2 double tap on 1st row any cell and input something while you are in editing mode then click on add row button then 2 cell will be focused.

Tamilarasan-Paranthaman commented 2 years ago

Hi @abdulrehmananwar,

Based on the provided information, we have checked your reported scenario. But we could not reproduce the reported issue. We have tested the following sample,

Sample Link: https://www.syncfusion.com/downloads/support/directtrac/general/ze/main1956230758

Please check the above sample and get back to us if you are still facing the same issue. If yes, please provide the following details,

• Issue reproducing video (If possible). • Sample which is your facing issue

It will be helpful for us to check on it and provide you with the solution at the earliest.

Regards, Tamilarasan

Tamilarasan-Paranthaman commented 2 years ago

Hi @abdulrehmananwar ,

Query: one more issue when i input extra text in cell textfield below scroll bar showing. why its showing against textfield

We have checked your reported issue and considered this as bug. We will include the changes in our upcoming weekly pub release which is scheduled to be rolled out on March 01, 2022.

Feedback Link: https://www.syncfusion.com/feedback/32958/horizontal-scrollbar-is-showing-when-typing-the-text-in-textfield-widget-more-than

We will let you know once it gets rolled out. We appreciate your patience until then. Please let us know if you require any further assistance.

Regards, Tamilarasan

Tamilarasan-Paranthaman commented 2 years ago

Hi @abdulrehmananwar,

Thank you for your patience.

We are glad to inform you that the fix has been included in our weekly pub release. Please update DataGrid package to 19.4.54 version.

Please let us know if you need further assistance on this.

Regards, Tamilarasan

abdulrehmananwar commented 2 years ago

Thanks issue resolved

abdulrehmananwar commented 2 years ago

image still is selecting multi cell when i remove and add rows.

abdulrehmananwar commented 2 years ago

step1- i have added three rows after input value in last cell i press save button which clear all the rows. step2. when all rows are clear i have again press add row button which add row when i have added third row then focus showing in that cell where before clearing the row.

Tamilarasan-Paranthaman commented 2 years ago

Hi @abdulrehmananwar,

Based on the provided reproducing steps, we have checked your reported scenario. But we could not reproduce the reported issue. We have tested the following sample, which you have already shared previously.

https://user-images.githubusercontent.com/93904422/158818218-a9e304dc-859c-4ffb-b295-1290e722d3b8.mp4

Sample Link: https://www.syncfusion.com/downloads/support/directtrac/general/ze/sample1332978527

Please check the above sample and get back to us if you are still facing the same issue. If yes, please provide the following details,

It will be helpful for us to check on it and provide you with the solution at the earliest.

Regards, Tamilarasan

abdulrehmananwar commented 2 years ago

below is my code when i add rows and remove last row then i cant edit any cell untill i add again rows.

class dgv_main extends StatefulWidget { const dgv_main({Key? key}) : super(key: key);

@override _dgv_mainState createState() => _dgv_mainState(); }

class _dgv_mainState extends State { late DgvDatasource _employeeDataSource; List<Map<String,dynamic>> _employees = []; List dataGridRows = []; List fieldlist = [field_model(field_name: 'item_name', tag: "Item Name",control_width: 200)];

late DataGridController _dataGridController; late CustomSelectionManager _customSelectionManager; GridNavigationMode navigationMode = GridNavigationMode.cell;

@override void initState() { super.initState(); _employees = getEmployeeData(); _employeeDataSource = DgvDatasource([], dataGridRows,fieldlist); _dataGridController = DataGridController(); _customSelectionManager = CustomSelectionManager(_dataGridController); }

@override Widget build(BuildContext context) { return Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ ElevatedButton( onPressed: () { FocusScope.of(context).notifyListeners(); _employees.add({}); _employeeDataSource = DgvDatasource(_employees, dataGridRows,fieldlist); _employeeDataSource.updateDataGridSource(); }, child: const Text('add new row')), ElevatedButton( onPressed: () { FocusScope.of(context).notifyListeners(); _dataGridController.endEdit(); _employees.clear(); _employeeDataSource.dataGridRows.clear(); _employeeDataSource = DgvDatasource(_employees, dataGridRows,fieldlist); _employeeDataSource.updateDataGridSource(); }, child: const Text('Save')), ], ), Expanded( child: Container( decoration: myBoxDecoration(), child: SfDataGrid( source: _employeeDataSource, allowEditing: true, controller: _dataGridController, columnWidthMode: ColumnWidthMode.fill, selectionMode: SelectionMode.single, onCellLongPress: (DataGridCellLongPressDetails details) async { _showPopup(context, details.rowColumnIndex.rowIndex, details.globalPosition); }, headerGridLinesVisibility: GridLinesVisibility.both, gridLinesVisibility: GridLinesVisibility.both, navigationMode: navigationMode, selectionManager: _customSelectionManager, editingGestureType: EditingGestureType.tap, columns: List.generate( fieldlist.length, (i) => GridColumn( width: fieldlist[i] .control_width, columnName: fieldlist[i] .field_name.toLowerCase(), label: Container( alignment: Alignment.center, child: Text( fieldlist[i].tag, )))), ), ), ), ], ); }

BoxDecoration myBoxDecoration() { return const BoxDecoration( border: Border.symmetric( horizontal: BorderSide(width: 1, color: Color(0xFFD6d6d6)), vertical: BorderSide.none)); }

List<Map<String,dynamic>> getEmployeeData() { return [ // Employee(10001, 'James', 'Project Lead', 70000), ]; }

void _showPopup(BuildContext context, int index, Offset position) async { //get the render box from the context final RenderBox renderBox = context.findRenderObject() as RenderBox; //get the global position, from the widget local position

//calculate the start point in this case, below the button final left = position.dx; final top = position.dy; //The right does not indicates the width final right = left + renderBox.size.width; const Map<String, IconData> _options = { 'Remove Row': Icons.remove_circle, };

//*show the menu final value = await showMenu( context: context, position: RelativeRect.fromLTRB(left, top, right, 0.0), items: _options.entries.map((entry) { return PopupMenuItem( value: entry.key, child: SizedBox( child: Row( children: [ Icon(entry.value, color: Colors.redAccent), const SizedBox(width: 10.0), Text(entry.key) ], ), ), onTap: () { if (entry.key == "Remove Row") { _employees.removeAt(index - 1); _employeeDataSource.dataGridRows.removeAt(index - 1); _employeeDataSource.updateDataGridSource(); } }, ); }).toList()); } }

class DgvDatasource extends DataGridSource { DgvDatasource(this._employees, this.dataGridRows,this._field_list) { dataGridRows = _employees .map((e) => DataGridRow(cells:

    List<DataGridCell>.generate(
        _field_list.length,
            (i) =>
            DataGridCell<dynamic>(columnName: _field_list[i].field_name.toLowerCase(), value: e[
            _field_list[i].field_name.toLowerCase()]))
    ))
        .toList();

}

// ignore: prefer_final_fields List<Map<String,dynamic>> _employees = []; List _field_list = []; List dataGridRows = [];

/// Helps to hold the new value of all editable widget. /// Based on the new value we will commit the new value into the corresponding /// [DataGridCell] on [onSubmitCell] method. dynamic newCellValue;

/// Help to control the editable text in [TextField] widget. TextEditingController editingController = TextEditingController();

@override List get rows => dataGridRows;

@override DataGridRowAdapter? buildRow(DataGridRow row) { return DataGridRowAdapter( cells: row.getCells().map((e) {

      return Container(child:
        Text(
          e.value.toString()!='null'?e.value.toString():
          "",
          overflow: TextOverflow.ellipsis,
        ),
      );
    }).toList());

}

@override void onCellSubmit(DataGridRow dataGridRow, RowColumnIndex rowColumnIndex, GridColumn column) {

String datavalue = _employees[rowColumnIndex.rowIndex]
[column.columnName.toLowerCase()].toString();
try
{
  dataGridRows[rowColumnIndex.rowIndex].getCells()[rowColumnIndex.columnIndex] =
      DataGridCell<dynamic>(columnName: column.columnName.toLowerCase(), value:
      datavalue!="null"?datavalue:""
      );
}
catch(Ex)
{

}

}

@override bool canSubmitCell(DataGridRow dataGridRow, RowColumnIndex rowColumnIndex, GridColumn column) { // Return false, to retain in edit mode. return true; // or super.canSubmitCell(dataGridRow, rowColumnIndex, column); } updateDataGridSource() { notifyListeners(); } @override Widget? buildEditWidget(DataGridRow dataGridRow, RowColumnIndex rowColumnIndex, GridColumn column, CellSubmit submitCell) { field_model fm = _field_list.where((element) => element.field_name.toLowerCase() == column.columnName.toLowerCase()) .single;

try{
  String value = _employees[rowColumnIndex.rowIndex][column.columnName.toLowerCase()].toString();
  editingController.text = value!= "null"?value:"" ;
}
catch(e)
{}

return
  Container(
      padding: EdgeInsets.only(left: 5,right: 5),
      child:
      TextField(
        autofocus: true,
        maxLines: 1,
        controller: editingController,
        onChanged: (String value) {
          _employees[rowColumnIndex.rowIndex][fm.field_name.toLowerCase()] = value.toString();
        },
        onSubmitted: (String value) {
          /// Call [CellSubmit] callback to fire the canSubmitCell and
          /// onCellSubmit to commit the new value in single place.
          submitCell();
        },

      )

  ) ;

}

}

class CustomSelectionManager extends RowSelectionManager { CustomSelectionManager(this.controller); DataGridController controller; @override void handleKeyEvent(RawKeyEvent keyEvent) { if (keyEvent.logicalKey == LogicalKeyboardKey.tab) { super.handleKeyEvent(keyEvent); controller.beginEdit(controller.currentCell); return; } super.handleKeyEvent(keyEvent); } }

class field_model { final String field_name; String tag; final double control_width;

field_model({required this.field_name, required this.tag,required this.control_width});

factory field_model.fromJson(Map<String, dynamic> json) { return field_model( field_name: json['field_name'], tag: json['tag'], control_width: json['control_width'].toDouble(), ); } }

Tamilarasan-Paranthaman commented 2 years ago

Hi @abdulrehmananwar,

We have checked your reported issue and logged this as a bug. We will include the changes in our upcoming weekly pub release which is scheduled to be rolled out on April 05, 2022. We will let you know once it gets rolled out. We appreciate your patience until then. You can follow up with the below feedback for further details,

Feedback Link: https://www.syncfusion.com/feedback/33593/other-cells-are-moving-into-edit-mode-when-removing-last-row-and-cell-in-that-row

Until then, you can call the end edit from the controller while removing the last row. Please check the following code snippet.


final value = await showMenu(
        context: context,
        position: RelativeRect.fromLTRB(left, top, right, 0.0),
        items: _options.entries.map((entry) {
          return PopupMenuItem(
            value: entry.key,
            child: SizedBox(
              child: Row(
                children: [
                  Icon(entry.value, color: Colors.redAccent),
                  const SizedBox(width: 10.0),
                  Text(entry.key)
                ],
              ),
            ),
            onTap: () {
              if (entry.key == "Remove Row") {
                _dataGridController.endEdit();
                _employees.removeAt(index - 1);
                _employeeDataSource.dataGridRows.removeAt(index - 1);
                _employeeDataSource.updateDataGridSource();
              }
            },
          );
        }).toList());

Regards, Tamilarasan

Tamilarasan-Paranthaman commented 2 years ago

Hi @abdulrehmananwar,

Thank you for your patience.

We are glad to inform you that the fix has been included in our weekly pub release. Please update DataGrid package to 20.1.48 version.

Please let us know if you need further assistance on this.

Regards,
Tamilarasan

abdulrehmananwar commented 2 years ago

thanks

abdulrehmananwar commented 1 year ago

i want to add row without add button. onCellSubmit event i want to do something like below.

if (rowColumnIndex.rowIndex+1== rows.length && newCellValue!=null) { // call add row function }

Tamilarasan-Paranthaman commented 1 year ago

Hi @abdulrehmananwar,

As per your requirement, we have prepared the sample for that. In that sample, we add the new row after submitting the last cell of the last row. Please check the following code snippet and sample.

void addNewRow() {
  _employees.add(Employee(0, '', '', 0));
  DataGridRow row = DataGridRow(cells: [
    DataGridCell<int>(columnName: 'id', value: 0),
    DataGridCell<String>(columnName: 'name', value: ''),
    DataGridCell<String>(columnName: 'designation', value: ''),
    DataGridCell<int>(columnName: 'salary', value: 0),
  ]);
  _employeeDataSource.dataGridRows.add(row);

  _employeeDataSource.updateDataGridSource();
}

class EmployeeDataSource extends DataGridSource {
  EmployeeDataSource(this.employees) {
    buildDataGridRow(employees);
  }

…

  @override
  Future<void> onCellSubmit(DataGridRow dataGridRow,
      RowColumnIndex rowColumnIndex, GridColumn column) async {
    final dynamic oldValue = dataGridRow
            .getCells()
            .firstWhereOrNull((DataGridCell dataGridCell) =>
                dataGridCell.columnName == column.columnName)
            ?.value ??
        '';

    final int dataRowIndex = dataGridRows.indexOf(dataGridRow);

    if (newCellValue == null || oldValue == newCellValue) {
      return;
    }

    if (column.columnName == 'id') {
      dataGridRows[dataRowIndex].getCells()[rowColumnIndex.columnIndex] =
          DataGridCell<int>(columnName: 'id', value: newCellValue);
      employees[dataRowIndex].id = newCellValue as int;
    } else if (column.columnName == 'name') {
      dataGridRows[dataRowIndex].getCells()[rowColumnIndex.columnIndex] =
          DataGridCell<String>(columnName: 'name', value: newCellValue);
      employees[dataRowIndex].name = newCellValue.toString();
    } else if (column.columnName == 'designation') {
      dataGridRows[dataRowIndex].getCells()[rowColumnIndex.columnIndex] =
          DataGridCell<String>(columnName: 'designation', value: newCellValue);
      employees[dataRowIndex].designation = newCellValue.toString();
    } else {
      dataGridRows[dataRowIndex].getCells()[rowColumnIndex.columnIndex] =
          DataGridCell<int>(columnName: 'salary', value: newCellValue);
      employees[dataRowIndex].salary = newCellValue as int;
      if (dataRowIndex == dataGridRows.indexOf(dataGridRows.last) &&
          newCellValue != null) {
        addNewRow();
      }
    }
  }

  void updateDataGridSource() {
    notifyListeners();
  }
}

Sample Link: https://www.syncfusion.com/downloads/support/directtrac/general/ze/sample1518568201

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

Regards, Tamilarasan

abdulrehmananwar commented 1 year ago

image when new row added next cell not auto in edit mode class SfDataGridDemo extends StatefulWidget { const SfDataGridDemo({Key? key}) : super(key: key);

@override SfDataGridDemoState createState() => SfDataGridDemoState(); }

FocusNode cellFocusNode = FocusNode(); FocusNode datagridFocusNode = FocusNode(); List _employees = []; late EmployeeDataSource _employeeDataSource; late CustomSelectionManager _customSelectionManager;

DataGridController dataGridController = DataGridController();

class SfDataGridDemoState extends State { @override void initState() { super.initState(); _employees = getEmployeeData(); _employeeDataSource = EmployeeDataSource(_employees); _customSelectionManager = new CustomSelectionManager(dataGridController); }

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Syncfusion Flutter DataGrid')), body: SfDataGrid( source: _employeeDataSource, controller: dataGridController, columns: getColumns, columnWidthMode: ColumnWidthMode.fill, allowEditing: true, editingGestureType: EditingGestureType.tap, navigationMode: GridNavigationMode.cell, selectionMode: SelectionMode.single, selectionManager: _customSelectionManager, gridLinesVisibility: GridLinesVisibility.both, headerGridLinesVisibility: GridLinesVisibility.both, ), ); }

abdulrehmananwar commented 1 year ago

also showing focus on two cells as in above picture

abdulrehmananwar commented 1 year ago

there are two major issue 1- showing focus on multiple cells when row added multiple time while pressing tab key. 2- when i press tab key after row added next focused cell should be in edit mode. image

Tamilarasan-Paranthaman commented 1 year ago

Hi @abdulrehmananwar,

The current cell is removed based on the previous cell index when key navigation. In that sample, we called the notifyListeners after submitting the last cell hence the DataGrid state is reset, and the previous index is removed there. That's why it doesn’t remove current cell properly while custom key navigation.

As per the DataGrid structure, the handleKeyEvent is called before the onCellSubmit. So, you are unable to achieve this (i.e., moving the next cell to edit mode with a single tab) in the onCellSubmit with the key navigation.

You can achieve this, by adding the new row in CustomSelectionManager.handleKeyEvent and call the state setter. After that, call the super.handleKeyEvent and dataGridController.beginEdit method in the addPostFrameCallback. Please check the following code snippet and sample.

In Datagrid:

late CustomSelectionManager _customSelectionManager;

class SfDataGridDemoState extends State<SfDataGridDemo> {
  @override
  void initState() {
    super.initState();
    _employees = getEmployeeData();
    _customSelectionManager = CustomSelectionManager(setState);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Syncfusion Flutter DataGrid')),
      body: SfDataGrid(
          source: _employeeDataSource,
          controller: dataGridController,
          columns: getColumns,
          selectionManager: _customSelectionManager,
          columnWidthMode: ColumnWidthMode.fill,
          allowEditing: true,
          navigationMode: GridNavigationMode.cell,
          selectionMode: SelectionMode.single,
          gridLinesVisibility: GridLinesVisibility.both,
          headerGridLinesVisibility: GridLinesVisibility.both),
    );
  }

In CustomSelectionManager:

class CustomSelectionManager extends RowSelectionManager {
  CustomSelectionManager(this.setState);
  StateSetter setState;
  @override
  void handleKeyEvent(RawKeyEvent keyEvent) {
    if (keyEvent.logicalKey == LogicalKeyboardKey.tab) {
      int lastRowIndex = _employeeDataSource.dataGridRows
          .indexOf(_employeeDataSource.dataGridRows.last);
      DataGridRow lastRow =
          _employeeDataSource.dataGridRows.elementAt(lastRowIndex);

      if (dataGridController.isCurrentCellInEditing &&
          dataGridController.currentCell.rowIndex == lastRowIndex &&
          dataGridController.currentCell.columnIndex ==
              lastRow.getCells().length - 1) {
        addNewRow();
        setState(() {});
      }

      WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
        super.handleKeyEvent(keyEvent);
        dataGridController.beginEdit(dataGridController.currentCell);
      });
    } else {
      super.handleKeyEvent(keyEvent);
    }
  }
}

In addNewRow:

void addNewRow() {
  _employees.add(Employee(0, '', '', 0));
  DataGridRow row = DataGridRow(cells: [
    DataGridCell<int>(columnName: 'id', value: 0),
    DataGridCell<String>(columnName: 'name', value: ''),
    DataGridCell<String>(columnName: 'designation', value: ''),
    DataGridCell<int>(columnName: 'salary', value: 0),
  ]);
  _employeeDataSource.dataGridRows.add(row);
}

Sample Link: https://www.syncfusion.com/downloads/support/directtrac/general/ze/sample1031430527

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

Regards, Tamilarasan

abdulrehmananwar commented 1 year ago

when i added 8 row i press tab key new row added butt focus remain in last row. image

Tamilarasan-Paranthaman commented 1 year ago

Hi @abdulrehmananwar,

Currently we are analyzing the reported issue. We will validate and update you with the details in two business days. i.e., August 10, 2022. We appreciate your patience until then.

Regards, Tamilarasan

Tamilarasan-Paranthaman commented 1 year ago

Hi @abdulrehmananwar,

Thank you for your patience.

We have validated your reported issue and logged this as a bug. We will include the changes in our weekly pub release which is scheduled to be rolled out on September 13, 2022. We will let you know once it gets rolled out. We appreciate your patience until then. You can follow up with the below feedback for further details,

Feedback Link: https://www.syncfusion.com/feedback/37313/the-current-cell-is-not-update-properly-while-adding-a-row-at-runtime-through-the

Regards, Tamilarasan

Tamilarasan-Paranthaman commented 1 year ago

Hi @abdulrehmananwar,

Sorry for the inconvenience. We have fixed the reported issue and will include the changes in our upcoming weekly patch release which is expected to be rolled out on October 11, 2022. We will update you once the release is rolled out and we appreciate your patience and understanding until then.

Regards, Tamilarasan

Tamilarasan-Paranthaman commented 1 year ago

Hi @abdulrehmananwar,

We are glad to inform you that the fix has been included in our weekly pub release for the mentioned issue. Please update the DataGrid package to version 20.3.49.

https://pub.dev/packages/syncfusion_flutter_datagrid/changelog

We thank you for your support and appreciate your patience in waiting for this update. Please get in touch with us if you require any further assistance.

Regards,
Tamilarasan