NAV TechDays 2018 Demos: Keyboard Shortcut Listener

The last of the NAV TechDays 2018 demo series comes with a little story.

While Waldo and I were preparing the “Evolution of the Titan” session, on Sunday before the conference, we were brainstorming the ideas of what would constitute a cool non-visual JavaScript demo. I wanted to showcase the things that JavaScript can do for you in control add-in context, but a less obvious thing. Everyone is expecting to see some cool visual demos, but I wanted to point out the vast possibilities in the non-visual area. Then Waldo asked me: can you make it run an action on a keypress, like post a document on F9?

And that was it! An amazingly cool demo that shows how you can do really cool stuff that falls beyond the visual realm.

Okay, I’ll calm down a bit. Keyboard shortcuts? Seriously? Well, unfortunately, yes. In NAV/BC web client (universal client included) there are almost no keyboard shortcuts. Microsoft is working on some improvements here, but the important thing, allowing developers to bind specific keyboard shortcuts to specific actions, is still conspicuously missing from NAV/BC.

So, I did this demo.

Let me first explain what the demo does.

Just like the profile picture demo, this one is a 1 x 1 “invisible” control add-in that injects some keyboard event listeners in the web client. However, since the web client in NAV 2018 and BC is full of IFRAMEs, I had to inject the event listeners all over the place, so the first thing that the demo does is that it locates all IFRAMEs in the current context and injects the capture event listener for keyboard events in all of them, so it kind of has the priority in handling keyboard input no matter where the focus currently is in the application. That’s the simple part.

The difficult part comes when the keyboard is successfully pressed. What then? In theory, you invoke an event in AL, and that event runs the action that you want to run, but this only works in theory. In practice, you cannot invoke a page action from code. I had two options.

The first one was to do duplicate quite a bit of code in AL simply to be able to demo a single keypress. Waldo preferred me showing document posting invocation through a keypress, but that would involve me copying quite a bit of code on the page so I could invoke exactly the same functionality that’s invoked when the Post action is clicked. However, I wanted to demo how easy it is to extend this by adding one simple line of AL code to bind another keystroke to another action. And since that would involve me duplicating large amounts of page code in front of the audience (and it will be a cold day in hell before you see me demo anything that involves code duplication) I chose another path.

And that other path involved quite a bit of smoke and mirrors. The only real way to have an action perform exactly the same thing that clicking an action in the client does is to actually click that action in the page. That’s something that JavaScript can do – simply locate an element and invoke the click on it, and there you go! But this comes with two problems. The first one is that there is no one-on-one way to uniquely identify a page action once the page is rendered. While actions in AL all have their unique names, once they are rendered in the page, there is nothing that uniquely identifies them that could be mapped to anything in the back end. Nothing at all. The other problem was that in both NAV 2018 and BC the action is not actually rendered on page unless it’s physically visible (either through the ribbon tab being accessed in NAV 2018, or submenu being expanded in BC). And this is practically a showstopper.

The first problem I solved by specifying the action binding through a combination of caption (something known in AL) and icon (also known in AL). If the action is rendered in the page, I can locate its DOM element through the icon it shows and caption it displays. That thing was fairly easy to solve, and you can see it in the demo code how I did it.

The second problem is entirely smoke and mirrors. What I did while demoing was that I expanded the tab (or opened the submenu) that contained the action I wanted to invoke, and then pressed the keyboard shortcut. So – I didn’t cheat with the actual keyboard shortcut, it really and truly was the keyboard shortcut that invoked the action. But I did cheat in the fact that if the action hadn’t been physically visible on the page, I wouldn’t have been able to invoke it.

Am I embarrassed because of this? Absolutely not. If anyone should be embarrassed of this, then it’s Microsoft, that from version to version keeps the remnants of the old “architecture” in place – instead of solving the problem on the AL level the way it should be solved (applying some nice, well-documented patterns, and getting rid of some ugly, well-known anti patterns like putting large chunks of code in pages) I wouldn’t have to invoke any voodoo here to make it work. However, with the state of the page “architecture” at where it still unfortunately is, I had no other option.

But it worked. And it doesn’t render this demo any less interesting. I actually find this demo the best and most useful of all demos, because it shows how you can capture a shortcut and then propagate it all the way back to AL where you can choose how to handle it. In this demo I didn’t propagate it – it was handled entirely in the front end – but it would take exactly one line of code to send the captured shortcut back to AL for processing.

And that’s it. A cool and simple demo

You can find all the code for this demo in this GitHub repo:

And again, there are two branches in there, master for BC, and nav2018 for – duh! – NAV 2018.

Happy keyboarding, and see you soon in another post! (most likely, not today, enough is enough )


Vjeko has been writing code for living since 1995, and he has shared his knowledge and experience in presentations, articles, blogs, and elsewhere since 2002. Hopelessly curious, passionate about technology, avid language learner no matter human or computer.

This Post Has One Comment

Leave a Reply