Reputation: 10898
I have an input box. When the text changes, I need to select the text. I understand that there are many events going on and I need to wait for them to finish. I put in a timeout and it works. However I don't want to rely on a constant time. Is there any way how to select the text when Angular is finished changing the text?
Example HTML:
<input type="text" value="{{txt}}">
<button ng-click="select()">Press</button>
Example JS:
angular.module('MyApp', []).controller('MyCtrl', function ($scope, $interval) {
$scope.txt = "Hello World";
$scope.select = function () {
$scope.txt = "Bye World";
// doesn't work, too early
document.querySelector("input").setSelectionRange(0, 4);
// works
$interval(function () {
document.querySelector("input").setSelectionRange(0, 4);
}, 10, 1);
}
});
EDIT: From the answers it looks like using timeouts (even with 0 delay) is a common practice, but the question remains whether this will guarantee that the selection happens after Angular finishes updating the text.
Upvotes: 1
Views: 1682
Reputation: 2599
$timeout 0 delay is in fact good enough since angular's dirty checking (and $digest cycle) happens synchronously. (0 delay would only fire up when the current process is free).
If you really really want to guarantee it, here's how:
angular.module('MyApp', []).controller('MyCtrl', function ($scope, $timeout) {
$scope.txt = "Hello World";
$scope.select = function () {
$timeout(function () {
$scope.$apply(function () {
$scope.txt = "Bye World";
});
document.querySelector("input").setSelectionRange(0, 4);
});
};
});
You have to use timeout to wrap the $apply, because the scope function would trigger a $digest and you cannot call $digest within a $digest cycle($apply calls $digest for you). $apply here guarantee the scope variable is updated, hence your setSelectionRange would only happen after the update.
Upvotes: 1
Reputation: 1694
If you do not want to use $timeout
, you can fire event with ng-blur
. A blur event fires when an element has lost focus.
HTML:
<div ng-controller="MyCtrl">
<form>
<input type="text" ng-blur="select()" value="{{txt}}">
<button>Press</button>
</form>
</div>
Script:
angular.module('MyApp', []).controller('MyCtrl', function ($scope, $interval) {
$scope.select = function () {
document.querySelector("input").setSelectionRange(0, 4);
}
});
Upvotes: 0
Reputation: 7179
You can use $timeout with 0 delay for this purpose.
$timeout(function(){
document.querySelector("input").setSelectionRange(0, 4);
});
Angular changes the DOM in next $digest
cycle, it is extremely fast, but it won't be available as soon as you run $scope.x = ??
. Normally we would use $timeout
to "wait" in this case.
Upvotes: 3