Our pure JavaScript Scheduler component


Post by cheradee »

Hi,

We have a use case where we want to hide/show context menu items based on the results of an async function by toggling the item's hidden property in the processItems function. It works for non-async functions, but for async functions, we noticed that the context menu does not wait for the async function to finish before showing the context menu, so all items end up visible.

Is there a way for us to hide/show context menu items based on the results of an async function?

Thanks,
Chardine


Post by tasnim »

Could you please show the code inside processItems?


Post by cheradee »

Here's a sample code:

processItems: async ({ items, resourceRecord, event }: {
  items: {
    createResourceDowntime: ScheduleMenuItemConfig
    createCrewDowntime: ScheduleMenuItemConfig
    relocateResource: ScheduleMenuItemConfig
    reassignResource: ScheduleMenuItemConfig
  },
  resourceRecord: {
    schedulerResourceType: SchedulerResourceType
    apiResourceId: number
  },
  event: {
    layerX: number,
    layerY: number,
    ObjID: number
  }
}): Promise<void> => {
  console.log(event, resourceRecord);

  return new Promise(resolve => {
    setTimeout(() => {
      items.relocateResource.hidden = true;
      items.reassignResource.hidden = true;
      console.log({...items});
      resolve(undefined);
    });
  });
}

console.log of items shows the relocateResource and reassignResource are hidden, but they still show in the context menu.


Post by tasnim »

Try this :

processItems({ items, resourceRecord, event, menu }) {
    console.log(event, resourceRecord);

setTimeout(() => {
    menu.menu.widgetMap.relocateResource.hidden = true;
    menu.menu.widgetMap.reassignResource.hidden = true;
});
}
  

Post by cheradee »

Hi,

What I provided is just a sample code to show that processItems is not waiting for an async function to finish. Our actual code has more complex logic that has to wait on an async function/Observable to hide/show items:

processItems: async ({ items, resourceRecord, event }: {
  items: {
    createResourceDowntime: ScheduleMenuItemConfig
    createCrewDowntime: ScheduleMenuItemConfig
    relocateResource: ScheduleMenuItemConfig
    reassignResource: ScheduleMenuItemConfig
  },
  resourceRecord: {
    schedulerResourceType: SchedulerResourceType
    apiResourceId: number
  },
  event: {
    layerX: number,
    layerY: number,
    ObjID: number
  }
}): Promise<void> => {
  if (resourceRecord.schedulerResourceType !== SchedulerResourceType.Crew) {
    items.createCrewDowntime.hidden = true;
  }

  if (resourceRecord.schedulerResourceType !== SchedulerResourceType.Resource) {
    items.createResourceDowntime.hidden = true;
    items.relocateResource.hidden = true; 
    items.reassignResource.hidden = true;
  }

  const hasCRUDAccess$ = this.accessService.userHasCRUDAccess(ObjectTypeEnum.Resource, AccessRightsEnum.CRUD);
  const resources$ = from(this.dataLayer.getResource(resourceRecord.apiResourceId));

  forkJoin([hasCRUDAccess$, resources$]).subscribe(result => {
    const [hasCRUDAccess, resources] = result;
    if (!hasCRUDAccess) {
      items.createResourceDowntime.hidden = true;
      items.createCrewDowntime.hidden = true;
      items.relocateResource.hidden = true;
      items.reassignResource.hidden = true;
      return;
    }

const arr = [event.layerX, event.layerY];
const date: Date = new Date(this.scheduler.instance.getDateFromXY(arr));
const res = nullableFind(resources, r => isDateTimeBetweenRange(date, {
  start: utcStrToDate(r.EffectiveFrom as unknown as string),
  end: utcStrToDate(r.EffectiveTo as unknown as string)
}));

if (!res) {
  // THIS SHOULD HIDE THE ITEMS
  items.relocateResource.hidden = true;
  items.reassignResource.hidden = true;
  console.log({...items});  // console.log shows the items have hidden=true, but they are still shown
}
  });
}

Post by tasnim »

You can use this event: https://bryntum.com/docs/gantt/api/Core/widget/Menu#event-beforeShow

Here is an example of how you can use it :

scheduler.features.eventMenu.menu.on('beforeShow', async ({ source }) => {
    const items = source.widgetMap;
    return new Promise(resolve => {
        setTimeout(() => {
            items.cutEvent.hidden = true;
            items.deleteEvent.hidden = true;
            console.log({...items});
            resolve(undefined);
        });
    });
});

Post by cheradee »

Hi,

The code above works, but it only has the "source" and "type" included in the event. We want the "resourceRecord" and "date" included in the event, like what "scheduleMenuBeforeShow" provides. We have tried

scheduler.features.scheduleMenu.menu.on('scheduleMenuBeforeShow', (event) => {...})

but it did not call our function.


Post by tasnim »

Hi,
It's really hard to achieve with this.
I've created a feature request to make the processItems async. Here it is: https://github.com/bryntum/support/issues/4855


Post Reply