search envelope-o feed check
Home Unanswered Active Tags New Question
user comment-o

Keyboard API: Cannot read properties of null (reading 'keyboard')

Asked by Anonymous
7 months ago.

Hi,
I'm using the following code from this tutorial (https://code.daypilot.org/68177/javascript-scheduler-how-to-use-the-keyboard-api)

onKeyDown: args => {
      if (args.originalEvent.code === "Tab") {
        args.originalEvent.preventDefault();
        if (args.originalEvent.shiftKey) {
          this.scheduler.control.keyboard.move("left");
        } else {
          this.scheduler.control.keyboard.move("right");
        }
      }
    },

    onEventEditKeyDown: args => {
      if (args.originalEvent.code === "Tab") {
        args.originalEvent.preventDefault();
        args.originalEvent.stopPropagation();
        args.submit();
        if (args.originalEvent.shiftKey) {
          this.scheduler.control.keyboard.move("left");
        }
        else {
          this.scheduler.control.keyboard.move("right");
        }
      }
    },
If I press the arrow or tab keys, I'm getting this error:
logging.service.ts:11 
        
       TypeError: Cannot read properties of null (reading 'keyboard')
    at DayPilot.Scheduler.onKeyDown (time-reporting-board.component.ts:294)
    at HTMLDocument.<anonymous> (daypilot-core.js:35)
    at ZoneDelegate.invokeTask (zone-evergreen.js:399)
    at Object.onInvokeTask (core.js:41686)
    at ZoneDelegate.invokeTask (zone-evergreen.js:398)
    at Zone.runTask (zone-evergreen.js:167)
    at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:480)
    at invokeTask (zone-evergreen.js:1621)
    at HTMLDocument.globalZoneAwareCallback (zone-evergreen.js:1658)
Comment posted by Dan Letecky [DayPilot]
7 months ago.

It looks like you override the "keyboard" property in the config (or somewhere else). Please make sure that you enable the keyboard navigation using "keyboardEnabled" property (and not "keyboard") like this:

config: DayPilot.SchedulerConfig {
  keyboardEnabled: true,
  // ...
}

The latest sandbox build (2021.4.5157) now includes SchedulerConfig.onKeyDown property. That will let you use a typed config object to prevent this problem.

Let me know if it didn't help.

Comment posted by Anonymous
7 months ago.

I'm not using keyboard. just keyboardEnabled.

I'm also using SchedulerConfig.onKeyDown, where the error occured. It's weird that it doesn't happen everytime.

 onKeyDown: args => {
      if (args.originalEvent.code === "Tab") {
        args.originalEvent.preventDefault();
        if (args.originalEvent.shiftKey) {
          this.scheduler.control.keyboard.move("left");
        } else {
          this.scheduler.control.keyboard.move("right");
        }
      }
    },
Comment posted by Dan Letecky [DayPilot]
7 months ago.

Thanks for the update. I did a few tests and this error suggests that "this.scheduler.control" is null, not "this.scheduler.control.keyboard".

The "control" property is assigned in the ngAfterViewInit phase and it will be undefined in earlier phases. However, the onKeyDown event handler is activated during Scheduler initialization which happens after "control" is set.

So normally you shouldn't see this error, unless you reuse onKeyDown for another event handler, for example.

I'm not able to reproduce the error using a testing project.

Depending on the logic, you can simply check if this.scheduler.control is null before using it to prevent the problem.

Anyway, you shouldn't see this error for arrow keys because they are not handled by this event handler.

Comment posted by Anonymous
7 months ago.
I'm getting another error. I don't know if they are related to each other. I will create a sample project and try to reproduce the errors
logging.service.ts:11 
        
       TypeError: Cannot read properties of null (reading 'scrollLeft')
    at DayPilot.Scheduler.wl (daypilot-core.js:27)
    at Object.I.kl (daypilot-core.js:34)
    at HTMLDocument.<anonymous> (daypilot-core.js:35)
    at ZoneDelegate.invokeTask (zone-evergreen.js:399)
    at Object.onInvokeTask (core.js:41686)
    at ZoneDelegate.invokeTask (zone-evergreen.js:398)
    at Zone.runTask (zone-evergreen.js:167)
    at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:480)
    at invokeTask (zone-evergreen.js:1621)
    at HTMLDocument.globalZoneAwareCallback (zone-evergreen.js:1658)
Comment posted by Dan Letecky [DayPilot]
7 months ago.

It looks like this might be caused by an event handler that survives a destroyed component. That would explain both errors. Please let me check that.

Answer posted by Dan Letecky [DayPilot]
7 months ago.

This should be fixed now in the latest sandbox build (2021.4.5158). Could you please give it a try?

Comment posted by Anonymous
7 months ago.

I think it's Ok now the latest sandbox. As you mentioned it's caused by an event handler that survives a destroyed component, because the error occures when I change from the component, that contains the scheduler and back to it.
When will you release the next version with that correction?
Thank you very much

Comment posted by Dan Letecky [DayPilot]
7 months ago.

Thanks for the update! The next release will be available on December 15:
https://release.daypilot.org/changes/js/

You can also work around this problem by changing the keyboardTarget to "component". This will bind the keyboard events to the component element instead of the document.

Comment posted by Anonymous
7 months ago.

If I change keyboardTarget to "component", the keyboard navigation with tab and arrow keys doesn't work anymore.

Comment posted by Dan Letecky [DayPilot]
7 months ago.

Well, it's just a workaround.

When it uses the component as the target, it requires that the focus has been set on the component. Otherwise the events will not bubble through the component event handlers.

You can set the initial focus like this:

ngAfterViewInit(): void {
  // ...
  const dp = <any>this.scheduler.control;
  dp.nav.top.focus();
} 

It will lose the focus again when you click outside the Scheduler component. You can handle the global keydown and reset the focus in that case. It will result in one lost keydown event but it will work.

ngAfterViewInit(): void {

  const dp = <any>this.scheduler.control;
  dp.nav.top.focus();

  document.addEventListener("keydown", () => {
    dp.nav.top.focus();
  });
} 

Maybe it is better to wait for the official release.

This question is more than 3 months old and has been closed. Please create a new question if you have anything to add.