lundi 29 décembre 2014

Focus text input after toggling visibility (using AngularJS directives)


I need a <div> with a text <input> to be toggled visible and then focus on the text element.


Pressing a button sets two conditions to true, one to show the parent element, and another to focus the input element.


I'm using two custom directives:



  • The ng-visible directive toggles the visibility property (visible / hidden) when evaluated truthful.

  • The ng-focus directive focuses the element when evaluated truthful.




The problem I ran into is my directive tries to focus the element too soon (before the block has had enough time to display as visibility: visible) and thus the focusing fails. Quick test reveals if a 1 second long $timeout delay is added, it works fine.


How can I ensure the focus directive waits until its visible before trying to focus the element?




Minor note: I am aware of ng-show / ng-hide (which works in my testing), but I need to use the CSS visibility property here instead.




HTML



<button ng-click="showMe = true; focusMe = true;"></button>

<div ng-visible="showMe">
<input type="text" ng-focus="focusMe"/>
</div>


Visibility Directive



app.directive('ngVisible', function($animate) {
return {
restrict: 'A',
multiElement: true,
link: function(scope, element, attr) {
scope.$watch(attr.ngVisible, function(value) {
if( value === true ) {
$animate.addClass(element, 'visible', function() {
$animate.removeClass(element, 'invisible', function() {
scope.$apply();
});
});
} else {
$animate.addClass(element, 'invisible', function() {
$animate.removeClass(element, 'visible', function() {
scope.$apply();
});
});
}
});
}
}
});


Focus Directive



app.directive('ngFocus', function($timeout, $parse) {
return {
link: function(scope, element, attr) {
var model = $parse(attr.ngFocus);

scope.$watch(model, function(value) {
if(value === true) {
$timeout(function() {
element[0].focus();
});
}
});

// Set attr value to false on blur event so it can be refocused
element.bind('blur', function() {
scope.$apply(model.assign(scope, false));
});
}
};
});




Aucun commentaire:

Enregistrer un commentaire