Grid with In-Cell editing general issues

14 posts, 0 answers
  1. Sam
    Sam avatar
    10 posts
    Member since:
    Dec 2017

    Posted 12 May 2020 Link to this post

    Hi

    I'm using this example from the docs for my project: https://www.telerik.com/kendo-react-ui/components/grid/editing/editing-in-cell/

    1) What is the editField in state used for in this example as it doesn't appear to affect anything

    2) I've only got one cell in the grid that I want to edit. While setting editable={false} on the other columns stops them from being editable it doesn't stop them from getting the onClick enterEdit, I thought I could be able to do my own custom filtering here but it appears the editable prop isn't passed through.

    3) How would you recommend sending data to the server after a user has updated the cell, I don't want to use a save changes button. I would like the data to be sent after the user has removed focus from the input so exitEdit seems perfect, but it doesn't fire unless you click off the row, if you click on another cell nothing happens.

    4) I have a default value for this cell that says required if it's blank. On clicking the cell it clears the value so the input is empty. If the user doesn't add anything it should add the required value back on so it can be seen in the grid again. It works when I click away from the row but clicking on another cell the value stays blank.

    I would be great if you could help me with these questions.

    Thanks

     

  2. Sam
    Sam avatar
    10 posts
    Member since:
    Dec 2017

    Posted 13 May 2020 in reply to Sam Link to this post

    I should also mention that I've got a rowClick function that selects the row. It seems this is interferring with the click away bit, if I turn off the set state during my row click then clicking on another cell works. I think it's because its trying to set two states at the same time.
  3. Sam
    Sam avatar
    10 posts
    Member since:
    Dec 2017

    Posted 13 May 2020 Link to this post

    I've solved 4) and my last comment. I'm trying to add an eventListener to my input now so it calls the exitEdit function when you press enter. That works but it seems to use the old state? Is there a similar prop to onItemChange for pressing enter on the input?
  4. Sam
    Sam avatar
    10 posts
    Member since:
    Dec 2017

    Posted 13 May 2020 Link to this post

    cellRender = (tdElement, cellProps) => {
      const dataItem = cellProps.dataItem;
      const cellField = cellProps.field;
      const inEditField = dataItem[this.editFieldName];
      let additionalProps = null;
     
      if (cellField && cellField === inEditField) {
        additionalProps = {
          ref: (td) => {
            const input = td && td.querySelector("input");
            const activeElement = document.activeElement;
     
            if (
              !input ||
              !activeElement ||
              input === activeElement ||
              !activeElement.contains(input)
            ) {
              return;
            }
     
            if (input.type === "checkbox") {
              input.focus();
            } else {
              input.select();
            }
     
            input.addEventListener("keypress", (e) => {
              if (e.key === "Enter") {
                this.exitEdit(e, dataItem, cellField);
              }
            });
          },
        };
      } else {
        if (cellField === "MyField") {
          additionalProps = {
            onClick: (e) => {
              this.enterEdit(e, dataItem, cellField);
            },
          };
        } else {
          additionalProps = {
            onClick: (e) => {
              this.exitEdit(e, dataItem, cellField);
            },
          };
        }
      }
  5. Stefan
    Admin
    Stefan avatar
    3034 posts

    Posted 13 May 2020 Link to this post

    Hello, Sam,

    Regarding the questions:

    1) The editField is used in order to know which field from the row is clicked and to place only that cell from the row in edit mode.

    2) The enterEdit called on the onClick event is programmatically set. We can suggest performing a check if the click field is the same as the one that can be edited and only then call the enterEdit method. As for the editable props, we can log an enhancement request to pass the prop down. The main reason why it is not set now is that we presume that inside the custom cell render, the developer knows which fields can be edit and which not.

    3) This is because the onBlur handler in the demo is attached to the rowRender. The same approach can be done to attach it to the cellRender and then it will be fired after the user leaves the cell.

    4 new) To clarify the issue is that on the keypress handler the dataItem that is received is the old one. If this is correct, we can see the value of e.targer which should hold the latest one:

            input.addEventListener("keypress", (e) => {
              if (e.key === "Enter") {
                this.exitEdit(e, dataItem, cellField);
              }
            });

    Regards,
    Stefan
    Progress Telerik

    Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
    Our thoughts here at Progress are with those affected by the outbreak.
  6. Sam
    Sam avatar
    10 posts
    Member since:
    Dec 2017

    Posted 13 May 2020 in reply to Stefan Link to this post

    Thanks for your reply I fixed 4) using your suggestion.

    I'm having trouble with input lag while I'm updating my cell when I have a lot of rows in my grid (above 10).

    const onItemChange = (event) => {
      const gridStateCopy = cloneDeep(gridState);
      const data = gridStateCopy.data.map((item) => {
        return item.WeeklyTimesheetsId === event.dataItem.WeeklyTimesheetsId
          ? { ...item, [event.field]: event.value }
          : item;
      });
     
      gridStateCopy.data = data;
      setGridState(gridStateCopy);
    };

     

    This is my itemChange function and it updates the whole grid every time you enter a new value, is there a better way of doing this?

  7. Stefan
    Admin
    Stefan avatar
    3034 posts

    Posted 14 May 2020 Link to this post

    Hello, Sam,

    I`m glad to hear that some of the issues are resolved.

    As for the input lag, the Grid should be updating instantly when typing. I extended our demo to have 60 items and there was no input lag observed:

    https://stackblitz.com/edit/react-9shc2l?file=app/sample-products.jsx

    The code on the onItemChange event looks good, I`m only not completely sure on how fast the cloneDeep method is. Is it possible to check if removing it will make a difference?

    Also, when testing for performance, please use the production build as React is times faster when building for production:

    https://reactjs.org/docs/optimizing-performance.html

    Regards,
    Stefan
    Progress Telerik

    Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
    Our thoughts here at Progress are with those affected by the outbreak.
  8. Sam
    Sam avatar
    10 posts
    Member since:
    Dec 2017

    Posted 18 May 2020 in reply to Stefan Link to this post

    We have 16 columns in our grid and I think that's what causes the issue. I'm not sure how to copy the gridState correctly without clonedeep.

    https://stackblitz.com/edit/react-9shc2l?file=app%2Fmain.jsx

     

  9. Stefan
    Admin
    Stefan avatar
    3034 posts

    Posted 19 May 2020 Link to this post

    Hello, Sam,

    I added 15 columns to the example and it was still updating as expected. Also, we have a columnVirtualization feature, which can be used in Grid with many columns:

    https://www.telerik.com/kendo-react-ui/components/grid/columns/column-virtualization/

    As for clone deep, I only wanted to remove it for the test, to see if it is causing a performance issue. Only if it is, we will need to replace it.

    If it is possible please reproduce the input lag in the example as this will help to locally test the reason for it.

    Regards,
    Stefan
    Progress Telerik

    Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
    Our thoughts here at Progress are with those affected by the outbreak.
  10. Di
    Di avatar
    3 posts
    Member since:
    Mar 2020

    Posted 22 Jun 2020 Link to this post

    Hi, is this problem solved? I'm having a similar input lag issue using this example https://www.telerik.com/kendo-react-ui/components/grid/editing/#toc-editing-options in our application. So I didn't have these rowRender or cellRender code from the in-cell editing example. Do I need these renderers to solve the input lag?

     

     

     

     

     

  11. Di
    Di avatar
    3 posts
    Member since:
    Mar 2020

    Posted 22 Jun 2020 in reply to Di Link to this post

    Actually I just noticed we have used an in-cell grid editing example in our application as well and it also has the lap problem. Maybe a little better than the inline version but very comparable. I added the columnVirtualization to the grid and set all the width. So far it has no improvement in my local env. I'm hoping this reduce the lap in the deployed env but haven't tried deploying the change yet. Is there a better way to do this so we don't experience the lag issue? Thank you.
  12. Stefan
    Admin
    Stefan avatar
    3034 posts

    Posted 23 Jun 2020 Link to this post

    Hello, Di,

    Is it possible to share an example or at least a code sample to observe the setup?

    Usually, the Grid should have no input lag, unless we are performing a resource-consuming operation each time the user types.

    The most common places to check are the cellRender, the render of the component that has the Grid, and the onItemChange event.

    Regards,
    Stefan
    Progress Telerik

    Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
    Our thoughts here at Progress are with those affected by the outbreak.
  13. Di
    Di avatar
    3 posts
    Member since:
    Mar 2020

    Posted 23 Jun 2020 in reply to Stefan Link to this post

    Hi Stefan,

    Here is a code example taking directly from our app. It's an inline editing so we don't have rowRender. We have onItemChange but I didn't see anything out of the ordinary. This is the kendo example we followed in this code example: https://www.telerik.com/kendo-react-ui/components/grid/editing/#toc-editing-options.

    Thank you,

    Di

     Code Example:

    /* eslint-disable no-param-reassign */
    /* eslint-disable react/destructuring-assignment */
    /* eslint-disable react/no-array-index-key */
    import React, { useState, useEffect } from 'react';
    import { useSelector, useDispatch } from 'react-redux';
    import { Grid, GridColumn } from '@progress/kendo-react-grid';
    import {
      getPortfolioOptions, loadPortfolios, updatePortfolioOptions, editPortfolioOptions,
    } from '../actions/allocatorActions';
    import MyCommandCell from './MyCommandCell';
    import DropDownCell from './DropDownCell';
    const PortfoliosOptions = () => {
      const [editID, setEditID] = useState(null);
      const [original, setOriginal] = useState({});
      const dispatch = useDispatch();
      useEffect(() => {
        dispatch(getPortfolioOptions());
      }, []);
      const {
        portsOptions, portOptions,
      } = useSelector(state => ({
        portsOptions: state.allocator.portsOptions,
        portOptions: state.allocator.portOptions,
      }));
      const rowClick = (event) => {
        setEditID(event.dataItem.portfolio_name);
      };
      const itemChange = (event) => {
        const inEditID = event.dataItem.portfolio_name;
        let data = [];
        let updated = {};
        const [target] = portsOptions.filter(item => item.portfolio_name === inEditID);
        if (event.field === 'rating_required') {
          updated = { ...target, [event.field]: event.value.value };
          data = portsOptions.map(item => (item.portfolio_name === inEditID ? { ...item, [event.field]: event.value.value } : item));
        } else {
          updated = { ...target, [event.field]: event.value };
          data = portsOptions.map(item => (item.portfolio_name === inEditID ? { ...item, [event.field]: event.value } : item));
        }
        dispatch(loadPortfolios(data));
        dispatch(updatePortfolioOptions(updated));
        setOriginal(target);
      };
      const update = () => {
        dispatch(editPortfolioOptions(portOptions));
        setEditID(null);
      };
      const cancel = () => {
        dispatch(getPortfolioOptions('Canceling...'));
        dispatch(updatePortfolioOptions(original));
        setEditID(null);
      };
      const CommandCell = MyCommandCell({
        update, cancel,
      });
      return (
        <div>
          {portsOptions != null && (
          <Grid
            style={{ width: '1450px', height: '400px' }}
            columnVirtualization
            editField="inEdit"
            data={portsOptions != null ? portsOptions.map(item => ({ ...item, inEdit: item.portfolio_name === editID })) : null}
            onRowClick={rowClick}
            onItemChange={itemChange}
          >
            <GridColumn field="portfolio_name" title="Portfolio" editable={false} width="80px" headerClassName="grid-header" />
            <GridColumn field="tactical" title="Tactical" editor="boolean" width="50px" headerClassName="grid-header" />
            <GridColumn field="preferred" title="Preferred" editor="boolean" width="50px" headerClassName="grid-header" />
            <GridColumn field="special_cash" title="Special Cash" editor="boolean" width="50px" headerClassName="grid-header" />
            <GridColumn field="rating_required" title="Rating Required" cell={DropDownCell} width="100px" headerClassName="grid-header" />
            <GridColumn field="notes" title="Notes" editor="text" width="930px" headerClassName="grid-header" />
            <GridColumn cell={CommandCell} width="160px" headerClassName="grid-header" />
          </Grid>
          )}
        </div>
      );
    };
    export default PortfoliosOptions;

     

     

  14. Stefan
    Admin
    Stefan avatar
    3034 posts

    Posted 24 Jun 2020 Link to this post

    Hello, Di,

    Thank you for the code.

    Based on the provided code I assume that maybe the dispatch on every itemChange could be causing this depending on how fast the store operations are.

    I can suggest keeping the updated data inside the component state (useState Hook) and only updating the store when the user clicks update in order to not send actions to the store each time the user types.

    Regards,
    Stefan
    Progress Telerik

    Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
    Our thoughts here at Progress are with those affected by the outbreak.
Back to Top