Our pure JavaScript Scheduler component


Post by tjmeal »

Dear all,

I have prepared a video where:

a) the side grid of the scheduler > if its collapsed > and i change the date from the scheduler ( which means will fetch data for the specific date > the autoWidth & autoHeight is broken.
b) If the grid is not collapse everything works as expected

Please find bellow the grid's settings.

const gridConfig = {
  selectionMode: {
    cell: false
  },
  cls: "b-unplannedgrid",
  flex: '0 1 450px',
  // collapsible : true,
  // title: 'Scheduler',
  // rowHeight: 85,
  //rowWidth: 450,
  // minWidth: 450,
  disableGridRowModelWarning: true,
  stripeFeature: true,
  rowCopyPasteFeature: true,
  cellMenuFeature: {
    processItems({items, record}) {
      if (record.serviceType === WS_TYPES.SERVICE_TYPE_TRANSFER) {

    if (record.status.id !== 18) {
      items.shareItem = {
        weight: 3,
        cls: 'b-separator',
        text: 'Share',
        icon: 'b-fa-share-alt',
        async onItem({source: grid, record: record, index: index, event: event}) {
          const selectedRows = grid.selectedRecords;
          if (selectedRows.length === 0) {
            await generalMethods.schedulerShareTransfer([record])
          } else {
            await generalMethods.schedulerShareTransfer(selectedRows);
          }
        },
      };
      items.assignOperator = {
        weight: 4,
        cls: 'b-separator',
        text: 'Assign Operator',
        icon: 'b-fa-share-square',
        async onItem({source: grid, record, index, event}) {
          grid.trigger('mmp_assignOperator', transfersWithSameStatus(grid.selectedRecords, record))
        },
      };
    }


    if (!record.isOutsourced) {

      items.requestInOrder = {
        weight: 5,
        cls: 'b-separator',
        text: 'Search In Order',
        icon: 'b-fa-search',
        async onItem({source: grid, record: record, index: index, event: event}) {
          const selectedRows = grid.selectedRecords;
          if (!selectedRows.length) {
            grid.trigger('mmp_sch_grid_searchInOrder', {record})
          } else {
            grid.trigger('mmp_sch_grid_searchInOrder', {selectedRows})
          }
        },
      };

      // items.requestInstant = {
      //   weight: 6,
      //   text: 'Instant Search',
      //   icon: 'b-fa-bolt',
      //   async onItem({source: grid, record: record, index: index, event: event}) {
      //     const selectedRows = grid.selectedRecords;
      //     if (!selectedRows.length) {
      //       grid.trigger('mmp_instantRequest', {record})
      //     } else {
      //       grid.trigger('mmp_instantRequest', {selectedRows})
      //     }
      //   },
      // };

      items.cancelRequest = {
        weight: 10,
        text: 'Cancel Request',
        icon: 'b-fa-times',
        async onItem({source: grid, record: record, index: index, event: event}) {
          const selectedRows = grid.selectedRecords;
          if (!selectedRows.length) {
            grid.trigger('mmp_cancelRequest', {record})
          } else {
            grid.trigger('mmp_cancelRequest', {selectedRows})
          }
        },
      };
    } else if (record.status.id === 14) {
      items.acceptUpdateFromOwner = {
        weight: 1,
        icon: 'b-fa-check',
        text: 'Accept Update',
        async onItem({source: grid, record: eventRecord, index: index, event: event}) {
          grid.trigger('mmp_acceptUpdateFromOwner', eventRecord)
        },
        // onItem({source, item, menu, domEvent, record, column, columnRecord, taskRecord, eventRecord, resourceRecord, assignmentRecord, checked }) {
        //   source.trigger('mmp_acceptUpdateFromOwner', null)
        // },
      };

      items.declineUpdateFromOwner = {
        weight: 2,
        text: 'Decline Update',
        icon: 'b-fa-ban',
        async onItem({source: sch, record}) {
          sch.trigger('mmp_rejectUpdateFromOwner', record)
        },
      };

    }

    // items.deleteItem = {
    //   text: record.isOutsourced && record.status.id !== 18 ? 'Reject' : "Delete",
    //   icon: 'b-fa-trash',
    //   cls: 'b-separator',
    //   async onItem({source: grid, record: eventRecord, index: index, event: event}) {
    //     const selectedRows = grid.selectedRecords;
    //     //todo if id = 18 different delete
    //     if (!selectedRows.length) {
    //       grid.trigger('mmp_deleteTransfer', eventRecord)
    //     } else {
    //       grid.trigger('mmp_deleteTransfer', selectedRows)
    //     }
    //   },
    // };

  } else if (record.serviceType === WS_TYPES.SERVICE_TYPE_REQUEST) {
    items.acceptRequest = {
      text: 'Accept',
      icon: 'b-fa-check',
      async onItem({source: grid, record: record, index: index, event: event}) {
        const selectedRows = grid.selectedRecords;
        if (!selectedRows.length) {
          grid.trigger('mmp_acceptRequest', {record})
        } else {
          grid.trigger('mmp_acceptRequest', {selectedRows})
        }
      },
    };

    items.rejectRequest = {
      text: 'Reject',
      icon: 'b-fa-ban',
      async onItem({source: grid, record: record, index: index, event: event}) {
        const selectedRows = grid.selectedRecords;
        if (!selectedRows.length) {
          grid.trigger('mmp_rejectRequest', {record})
        } else {
          grid.trigger('mmp_rejectRequest', {selectedRows})
        }
      },
    };
  }

},
items: {
  cut: false,
  paste: false,
  copy: false,
  removeRow: false
}
  },
  filterBarFeature: {
    compactMode: true
  },
  groupFeature: {
    headerHeight: 50,
    field: 'serviceType',
    renderer({groupRowFor, column}) {
      if (column.parentIndex === 0) {
        return `${groupRowFor}`;
      }
      return '';
    }
  },
  listeners: {
    cellMenuBeforeShow({record}) {
      // Blocks right click on Group Headers (Request, Transfer etc)
      if (record.isSpecialRow) {
        return false;
      }
    },

// Add a listener for row clicks
cellDblClick({record, source}) {
  if (record.serviceType === WS_TYPES.SERVICE_TYPE_TRANSFER) {
    showPopupComponent(source, record, "scheduler")
  }
}
  },
  cellTooltipFeature: {
    // Time that mouse needs to be over cell before tooltip is shown
    hoverDelay: 500,
    // Time after mouse out to hide the tooltip, 0 = instantly
    hideDelay: 0,
    tooltipRenderer({record, tip}) {
      return gridTransferToolTip(record);
    }
  },
  // Columns
  columns: [
    {
      type: 'template',
      field: "template",
      // flex: 0.7,
      text: 'Services',
      filterable: false,
      autoWidth: true,
      autoHeight: true,
      maxWidth: 300,
      readOnly: true,
      template: ({record}) => {
        if (record.serviceType === WS_TYPES.SERVICE_TYPE_TRANSFER) {
          return gridTransferItem(record)
        } else if (record.serviceType === WS_TYPES.SERVICE_TYPE_REQUEST) {
          return gridTransferRequestItem(record);
        }
      },
    },
    {
      text: 'Vehicle',
      field: 'vehicleCategory.name',
      align: 'center',
      autoWidth: true,
      autoHeight: true,
      readOnly: true,
      filterable: true,
      minWidth: 95,
      maxWidth: 150,
    },
    {
      text: 'Status',
      field: 'status',
      align: 'center',
      autoWidth: true,
      autoHeight: true,
      readOnly: true,
      filterable: true,
      sortable: false,
      minWidth: 90,
      maxWidth: 150,
      renderer({value, record}) {
        // Because i am using on model datasource = status.name > i only have name here (because sorting wasn't working)
        if (record.status?.id === 8) {
          return value?.name + " " + record.operatorsRequested;
        } else {
          return value?.name;
        }
        // return value;
      }
    },
    {
      text: 'Client',
      field: 'client',
      align: 'center',
      autoWidth: true,
      autoHeight: true,
      readOnly: true,
      filterable: true,
      sortable: false,
      minWidth: 90,
      maxWidth: 150,
      renderer({value, record}) {
        return value?.name?.slice(0, 25) + '...';
      }
    },
  ],
}
Attachments
Screen Recording 2025-06-10 at 09.13.04.mov
(4.26 MiB) Downloaded 4 times

Post by tasnim »

Hi,

It seems like the issue might be related to the autoWidth and autoHeight settings in your grid configuration. When the grid is collapsed, these settings might not be recalculating correctly upon data fetch, leading to misalignment.

To address this, you can try explicitly setting the width and height of the grid or columns when the grid is collapsed and then adjust them back when expanded. Alternatively, you can force a refresh of the grid layout after fetching new data to ensure the dimensions are recalculated correctly.

Here's a simple approach to refresh the grid layout:

scheduler.refresh();

You can call this method after the data fetch to ensure the layout is updated. If the issue persists, consider checking if any CSS styles are affecting the grid's layout when collapsed.

If you need further assistance, please provide more details or a runnable test case showing how you handle the data fetch and grid collapse/expand actions.

Best regards,
Tasnim

How to ask for help? Please read our Support Policy


Post by tjmeal »

What you send me isn't working.

But i managed to fix it somehow but again is not perfect. > i used the following code > but the problem is > it shows first the data unstructured > and then use fit size (see the video) > Is there any way to fix that delay ?

  const onToggleOrderList = useCallback(() => {
    gridRef.current.instance.hidden = !gridRef.current.instance.hidden;
    gridRef.current.instance.columns.getById("services-column").resizeToFitContent();

//gridRef.current.instance.columns.resizeColumnsToFitContent();
  }, [gr
Attachments
Screen Recording 2025-06-10 at 12.44.11.mov
(2.7 MiB) Downloaded 3 times

Post by tasnim »

You could try this

gridRef.current.instance.refreshRows()

instead of this

gridRef.current.instance.columns.getById("services-column").resizeToFitContent();

Does that help?

Best regards,
Tasnim

How to ask for help? Please read our Support Policy


Post by tjmeal »

Perfect,

Thank you so much !!


Post Reply