Last active
November 10, 2016 06:08
-
-
Save davidsargent/eee22ed385ce42a7fc1adbf74f70197c to your computer and use it in GitHub Desktop.
Angular 1 directive to auto-focus next input when current input becomes valid
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
'use strict'; | |
app.directive('autoNext', autoNext); | |
/////////////// | |
/** | |
* autoNext | |
* | |
* Should be placed on an <input> | |
*/ | |
function autoNext() { | |
return { | |
restrict : 'A', | |
require : ['ngModel'], | |
link : link | |
}; | |
// LINK Function | |
function link( $scope, $elem, attrs, ctrls ) { | |
const model = ctrls[0]; | |
let focusInputCurrentAttempt = 0; | |
// CHECK if $elem is valid | |
// ( Without custom validation this will be valid after the first character entered ) | |
$scope.next = function() { | |
return model.$viewValue && model.$valid; | |
}; | |
// WATCH next and go to the next input if the current one is valid | |
$scope.$watch( $scope.next, function nextWatch( newVal ) { | |
if ( newVal ) { | |
focusInputCurrentAttempt = 0; | |
recurseToFocusInput($elem); | |
} | |
}); | |
/////////////// | |
/** | |
* From the target element, see if the next sibling element is an <input> | |
* If yes, focus it and return. | |
* If not, recursively go up its DOM parents until we find a 'next' DOM element | |
* with an <input> descendant to focus. | |
* | |
* NOTE: The amount of parent DOM traversal attempts is capped. This may be adjusted. | |
* | |
* @param {Object} $target - The element to search from | |
* @param {Number} maxAttempts - The max number of times to traverse the DOM and get parent elements | |
*/ | |
function recurseToFocusInput( $target, maxAttempts = 4 ) { | |
// RETURN if max parent attempts have been met | |
// We don't want to traverse up the DOM past a logical amount of tries | |
if ( focusInputCurrentAttempt>=maxAttempts ) return; | |
// Store next <input> | |
// Either it is the immediate next sibling element | |
// or we need to grab the parent and see if its next sibling has an <input> | |
let $nextInput = $target.next('input').length | |
? $target.next('input') | |
: $target.parent().next('div').find('input').eq(0); | |
// If an <input> was found, focus it | |
if ( $nextInput.length ) { | |
$nextInput.focus(); | |
} | |
else { | |
// Increment max-attempts counter | |
focusInputCurrentAttempt++; | |
// Get next parent element | |
$target = $target.parent(); | |
// Re-run next pass | |
recurseToFocusInput($target, maxAttempts); | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
Assumes you have validation on the <input> elements, | |
otherwise it will focus the next element after typing | |
one character ( as the field will be valid ). | |
For example, if you had a 4 digit month field, | |
it would need to be invalid until length is 4. | |
At that point it would auto-focus the next field | |
when it becomes valid. | |
--> | |
<div> | |
<input type="text" auto-next ng-model="set.input1"> | |
<input type="text" auto-next ng-model="set.input2"> | |
</div> | |
<div> | |
<input type="text" auto-next ng-model="set.input3"> | |
</div> | |
<div> | |
<div> | |
<input type="text" auto-next ng-model="set.input4"> | |
</div> | |
</div> | |
<input type="text" auto-next ng-model="set.input5"> | |
<input type="text" ng-model="set.input6"> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment