How to Ensure Project Success with Telerik

Step-by-Step Tutorial Using Imaginet’s Telerik Mastery

By: Evan Bosscher

At Imaginet, we love being the best at software innovation. While we traditionally have been one of the best in the world on the Microsoft platform for over 19 years, we are never shy about going deep and being world-class experts in other state-of-the-art tools and technologies – especially Telerik technologies.

As a Telerik Gold Partner, our Imaginet team has been developing enterprise-level solutions with Telerik products for more than five years. While Telerik technologies like Kendo UI provide enormous out-of-the-box capabilities to jump start your development project, there are times when we have to put our Telerik mastery into action to go outside the box in order to get exactly what we want in the application we’re coding.

Here is a just one simple example of how we recently leveraged our Telerik mastery with Kendo UI to help port a windows based data entry application to the web.

Kendo UI Grid: Keyboard Enabled Multi-Select

When we started the application porting project, we had already decided to use Kendo UI for data visualization and manipulation on the web site. I like working with Kendo UI, as it does many things very well. However, when it doesn’t do something out-of-the-box, it can be a bit of work to figure out how to customize it yourself. So when I was asked to keyboard-enable the multi-select feature of the Kendo UI grid, I figured Kendo UI would have something out-of-the-box that I could leverage to accomplish this goal.

To get started, I opened the source file and added “navigatable: true” to the grid so it would start using the keyboard for navigation. I expected that it would perform selections and deselections using the standard multi-select keyboard combinations, but this wasn’t the case. The keyboard support that Kendo UI provides out-of-the-box was limited to SPACE, which cleared all previous selections and selected the row for the current cell, and CTRL + SPACE, which toggled row selection for the currently selected cell.

The functionality needed was something akin to how Microsoft Excel handles multi-select. So off to the drawing board I went! There were a few challenges up front:

  1. Which keyboard events should be used to do the selection?
  2. Which keyboard events will Kendo UI let me play with?
  3. Can I improve on the default Excel multi-select behaviour?

I decided to use the following keyboard combinations to enable multi-select:

  1. SPACE would change the selection to be the row containing the current cell (default)
  2. CTRL + SPACE would toggle selection of a single row (default)
  3. CTRL + A would select all rows
  4. ESC would deselect all rows (I might add support for CTRL + SHIFT + A)
  5. SHIFT + UP would select contiguous rows above and including the origin row.
  6. SHIFT + DOWN would select contiguous rows below and including the origin row.

The next question was: which event do I use to do the binding? The keypress event wasn’t an option because it doesn’t get raised when the arrow keys are pressed, leaving the keyup and keydown events. The keydown event was the obvious choice since it repeats when a user holds down a key, so I would be notified multiple times if a user was holding down an arrow key.

Simple right? Wrong.

I’m not 100% sure, but it appeared that the Kendo UI Grid suppresses the propagation of the keydown event for the arrow keys because I never saw the events. This left me with the option to use either the keyup event exclusively or some hybrid of keydown and keyup, which is what I finally ended up using to support the tracking I needed to do.

Now, all that was left was to add handlers for the different keys. I started with the Select All feature, and in the keydown handler, I checked to see if the “A” key was being pressed and if the SHIFT key was being held down. If so, I selected all rows in the grid.

element = $(event.target);
if (element.hasClass("k-grid") === false) {
element = element.closest(".k-grid");
}


grid = element ? element.data(imaginet.constants.kendo.grid) : null;
switch (event.which) {
case imaginet.constants.keys.A:
if (event.ctrlKey === true) {
grid.select(grid.table.find("tr"));
}
break;
}

As you may expect, this worked. All rows in the grid were selected. What I didn’t expect was that it would ALSO select all of the other text on the page. The browser decided it also had to respond to the CTRL + A and select all of the page contents. I quickly fixed this issue by preventing the default behavior, and the Select All feature was complete:

switch (event.which) {
case imaginet.constants.keys.A:
if (event.ctrlKey === true) {
grid.select(grid.table.find("tr"));
event.preventDefault();
}
break;
}

The Deselect All feature was equally as simple:

switch (event.which) {
case imaginet.constants.keys.ESC:
grid.clearSelection();
;break;
}

Finally, I had to figure out how to implement the Contiguous Selection feature – which raised additional questions: How does that work in general? How does that work when I can’t react to the keydown event for the arrow keys? To start, I looked at how Microsoft Excel does multi-select:

  1. When I press the SHIFT key, it doesn’t select the current row.
  2. If I hold the SHIFT key and press the up or down arrow key, it selects the row I was in originally (origin row) and the row in the direction I pressed the arrow key from the origin row.
  3. If I continue to hold the SHIFT key, additional presses of the same arrow key selected additional rows in the same direction.
  4.  If I continued to hold SHIFT and changed to the opposite arrow key, previously selected rows became deselected as I left them.
  5. If I continued to hold SHIFT and cross the origin row, the selection went in the other direction.
  6. If I released SHIFT, the selection was retained.
  7.  If I pressed an arrow key while not holding SHIFT, all rows were deselected.

I decided, however, that automatically deselecting rows was not something I wanted to have happen. Since selecting items is the result of a user decision, then deselecting items should also be the result of a user decision, not a side effect of navigation. This gave us our baseline from which to work.

To start, I needed to be able to determine what our origin row was. That can be accomplished by recording the index of the row containing the currently active grid cell when the SHIFT key is pressed and clearing it when the key is released.

switch (event.which) {
case imaginet.constants.keys.SHIFT:
if(row) {
element.attr("data-originIndex", row.index());
}
break;
}

Remember that we have to use the keyup events in order to trap the arrow keys, which only happens after a user releases the key. This could happen after a user has been pressing the key for a while, so we need to be able to find out the distance a user travelled and react to it based not only on where the origin of the contiguous select is, but also where the user last released an arrow key.

The easiest way to show you how we accomplished this is see the rest of the code along with all the calculations in this live example of the multi-select keyboard bindings in action: http://plnkr.co/edit/I5PNkCnXfLkxulJZJLOZ?p=preview.

Happy coding!

 


 

Need help with Telerik Development Services?

Together, Imaginet and Telerik have jointly built innovative and award-winning software products together. As a Gold level Telerik partner, awarded to only four select consulting firms, Imaginet’s team has completed projects using virtually every control in the Telerik’s toolbox. From KendoUI to Angular to Sitefinity and everything in between.

Visit our Telerik Development Services to learn more.

Imaginet_lightblue_telerikdevservices_371x40

 


 

Imaginet is your trusted technology partner who turns your business innovation ideas into reality. 18+ years | 1100+ satisfied customers | 2500+ successful engagements. Located in Dallas (Irving), Winnipeg, Calgary, and St. Louis. Services offered worldwide. Contact us today at info@imaginet.com or 1-800-989-6022.

 

Evan Bosscher

About Evan Bosscher

Leave a Reply