AngularJs: Keyboard navigation using TAB key in different groups/forms/divs
Solution 1
Many thanks @Kiran Nawaleand @Gökhan Kurt for guiding me to the solution.
I have created a generic directive which is reusable for any angular app.
Dependencies
- Jquery
- AngularJs
In directive I have added comments which will guide you through the way the directive is working.
How to use?
Add the given below attributes and the directive in your element
tab-man tab-index="0" tab-group="g1"
tab-man : the directive
tab-index : it is the index of the element in the group
tab-group : name of the group
Note:
There should always be a
0
index in every group otherwise the cycle will not restart.If any index is skipped like
0,1,2,4...
(3
is skipped) then after 2 the focus move to0
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.min.js"></script>
<script>
var app = angular.module('myapp', []); /// angular app
app.directive('tabMan', function() { ///directive
return {
restrict: 'A', /// accessible only by attribute
scope: {}, /// scope is not needed
link: function(scope, element, attrs) { ///link function to add key-down event on the target element
var gotoElement = function(grp, idx) {
/// get next element
var nextElement = $("input[tab-group='" + grp + "'][tab-index='" + idx + "']")[0];
/// if there is not next element then go to the 0 index
if (nextElement == undefined) {
if (idx != 0) { /// if the index is 0 then do not do any thing
gotoElement(grp, 0); /// restart the cycle
}
} else {
nextElement.focus(); /// succesfully give focus to the next
}
};
var tabIndex = attrs.tabIndex;
var tabGroup = attrs.tabGroup;
$(element).keydown(function(event) {
if (event.keyCode == 9) { /// go inside if tab key is pressed
var tIdx = $(event.target).attr("tab-index"); /// get the current index of element
var nextTid = parseInt(tIdx.toString()) + 1; /// get the next index of element
nextTid = Number(nextTid); /// turn the index into number
var tGrp = $(event.target).attr("tab-group"); /// get the group of the element
gotoElement(tGrp, nextTid); /// go to the next element
/// the work of tab is done by the directive so remove the default and stop the bubbeling
event.stopPropagation()
event.preventDefault();
}
});
}
};
});
</script>
</head>
<body ng-app="myapp">
<div role="group" tabindex="-1">
<h1>Group 1</h1>
<br>
<input type="text" tab-man tab-index="0" tab-group="g1" />
<br>
<input type="text" tab-man tab-index="5" tab-group="g1" />
<br>
<input type="text" tab-man tab-man tab-index="2" tab-group="g1" />
<br>
<input type="text" tab-man tab-index="3" tab-group="g1" />
<br>
<input type="text" tab-man tab-index="4" tab-group="g1" />
<br>
<input type="text" tab-man tab-index="1" tab-group="g1" />
<br>
<button>Submit</button>
</div>
<hr>
<div>
<div role="group" tabindex="-1">
<h1>Group 2</h1>
<br>
<input type="text" tab-man tab-index="0" tab-group="g2" />
<br>
<input type="text" tab-man tab-index="5" tab-group="g2" />
<br>
<input type="text" tab-man tab-man tab-index="2" tab-group="g2" />
<br>
<input type="text" tab-man tab-index="3" tab-group="g2" />
<br>
<input type="text" tab-man tab-index="4" tab-group="g2" />
<br>
<input type="text" tab-man tab-index="1" tab-group="g2" />
<br>
<button>Submit</button>
</div>
</div>
</body>
Solution 2
Unfortunately, you can't do that without JavaScript.
Here I have implemented the JavaScript/jQuery code to handle tabbing between two groups.
Also please make a note that For moving to the second group you/user have to decide when to move to second group of inputs.
HTML
<div id="group-1" role="group" tabindex="0">
<h1>Group 1</h1>
<br>
<input type="text" tabindex="1" />
<br>
<input type="text" tabindex="1" />
<br>
<input type="text" tabindex="1" />
<br>
<input type="text" tabindex="1" />
<br>
<input type="text" tabindex="1" />
<br>
<input type="text" tabindex="1" />
<br>
<input type="button" value="submit" tabindex="1" />
<div id="focusguard-1" tabindex="1"></div>
</div>
<hr>
<div>
<div id="group-2" role="group" tabindex="0">
<h1>Group 2</h1>
<br>
<input type="text" tabindex="1" />
<br>
<input type="text" tabindex="1" />
<br>
<input type="text" tabindex="1" />
<br>
<input type="text" tabindex="1" />
<br>
<input type="text" tabindex="1" />
<br>
<input type="text" tabindex="1" />
<br>
<input type="button" value="submit" tabindex="1" />
<div id="focusguard-2" tabindex="1"></div>
</div>
</div>
JavaScript/JQuery
$('#focusguard-1').on('focus', function() {
$('#group-1 input:first').focus();
});
$('#focusguard-2').on('focus', function() {
console.log("Focus in");
$('#group-2 input:first').focus();
});
Solution 3
tabindex works globally in a window. You can achieve what you want with javascript. Your groups must have a class "closedFocus" and your elements should have a tabIndex. You can change the code to achieve the effect you want:
$(".closedFocusGroup [tabindex]").on("keydown", function(e) {
if (e.which == 9) {
var parentGroup = this.closest(".closedFocusGroup");
var allChildren = $(parentGroup).find("[tabindex]");
allChildren.sort(function(a,b){ return a.tabIndex-b.tabIndex});
var thisIndex = allChildren.index(this);
var nextIndex = (thisIndex + 1) % allChildren.length;
var nextItem = allChildren[nextIndex];
if (nextItem) nextItem.focus();
e.preventDefault();
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div role="group" class="closedFocusGroup" tabindex="-1">
<h1>Group 1</h1>
<br>
<input type="text" tabindex="1" />
<br>
<input type="text" tabindex="6" />
<br>
<input type="text" tabindex="4" />
<br>
<input type="text" tabindex="2" />
<br>
<input type="text" tabindex="5" />
<br>
<input type="text" tabindex="2" />
<br>
<button tabindex="7">Submit</button>
</div>
<hr>
<div>
<div role="group" class="closedFocusGroup" tabindex="-1">
<h1>Group 2</h1>
<br>
<input type="text" tabindex="1" />
<br>
<input type="text" tabindex="6" />
<br>
<input type="text" tabindex="4" />
<br>
<input type="text" tabindex="2" />
<br>
<input type="text" tabindex="5" />
<br>
<input type="text" tabindex="2" />
<br>
<button tabindex="7">Submit</button>
</div>
</div>
Vikas Bansal
javascript, typescript, ReactJs, Angularjs, Nodejs, Electronjs.... waiting for the next :) :P :D
Updated on July 22, 2022Comments
-
Vikas Bansal almost 2 years
I have two groups and I want to separate navigation for them and on last tab control of the group when tab key is pressed then the iteration cycle should be restarted and the focus should move to the initial element of the group (which would be the 0 index)
In given below Example I have added two groups and in the group I have added some text-boxes and assigned not serial order.
Problems
- When Pressing tab focus is moving across the groups
- On the last index the cycle is not restarting, instead its going in the address bar
Note: I am making an angularjs app and this is just a dummy to provide a clear view of my problem
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div role="group" tabindex="-1"> <h1>Group 1</h1> <br> <input type="text" tabindex="1" /> <br> <input type="text" tabindex="6" /> <br> <input type="text" tabindex="4" /> <br> <input type="text" tabindex="2" /> <br> <input type="text" tabindex="5" /> <br> <input type="text" tabindex="2" /> <br> <button tabindex="7">Submit</button> </div> <hr> <div> <div role="group" tabindex="-1"> <h1>Group 2</h1> <br> <input type="text" tabindex="1" /> <br> <input type="text" tabindex="6" /> <br> <input type="text" tabindex="4" /> <br> <input type="text" tabindex="2" /> <br> <input type="text" tabindex="5" /> <br> <input type="text" tabindex="2" /> <br> <button tabindex="7">Submit</button> </div> </div> </body> </html>
-
Neelam Sharma almost 7 yearsI have tried above code to restart, but the cursor navigate top to down, I need cursor movement left-to-right then down, how can I achieve it
-
Vikas Bansal almost 7 yearsyou can set
tab-index="2"
-
Neelam Sharma almost 7 yearsThanks, it working fine to restart the cycle, but my issue is : stackoverflow.com/questions/44455082/…, how can I navigate left-to-right then down when design is in different div using your directive?