Robware Software by Rob

Displaying the keyboard on iOS when showing a textbox with AngularJS

Consider the following HTML and JavaScript:

<div data-ng-controller="controller">
	<button data-ng-click="showTb=true">
		Show TextBox
	</button>

	<div data-ng-show="showTb">
		<form>
			<input type="text" />
		</form>
	</div>
</div>
angular.module('module')
	.controller("controller", [
		"$scope", "$timeout", function($scope, $timeout) {
			$scope.showTb=false;
		}
	]);

This is a basic example of a simple AngularJS setup to show a textbox. Now we'll edit it to fire the focus event.

<div data-ng-controller="controller">
	<button data-ng-click="displayTb()">
		Show TextBox
	</button>

	<div data-ng-show="showTb">
		<form>
			<input type="text" id="textBox" />
		</form>
	</div>
</div>
angular.module('module')
	.controller("controller", [
		"$scope", "$timeout", function($scope, $timeout) {
			$scope.showTb=false;
			
			var displayTb=function(){
				$scope.showTb=true;
				
				var element = window.document.getElementById("textBox");
				element.focus();
			}
		}
	]);

However, this won't work.

The reason it fails is because the model hasn't fully updated and show the textbox hasn't shown yet. The view doesn't update until the function has completed, so when the element is focussed it's not visible. Now, you may think about adding the code to focus in a timeout, or watch (which I know works for Android), to work around this, but that also won't work because iOS won't allow you to focus an element entirely at your will; you can only focus on a click event. Thankfully this can be the click event of any element.

This is how I got around the issue:

<div data-ng-controller="controller">
	<button id="displayTb">
		Show TextBox
	</button>

	<div data-ng-show="showTb">
		<form>
			<input type="text" id="textBox" />
		</form>
	</div>
</div>
angular.module('module')
	.controller("controller", [
		"$scope", "$timeout", function($scope, $timeout) {
			$scope.showTb=false;
			
			var displayTb=function(){
				$scope.showTb=true;
			}
		};
		
		$("#displayTb").on('click',function () {
			displayTb();
			$scope.$apply();
			if ($scope.showTb)
				$("#textBox").focus();
			else
				$("#textBox").blur();
		});
	]);

This uses jQuery to hook in to the click event, allowing us to call a focus() in iOS. It calls the Angular function we wrote to show the textbox and then tells the Angular scope to apply the model changes to the view. Without the $scope.$apply() the model won't update. There may be a more suitable way to do this, but time constraints prevented me from looking in to it further.

Posted on Tuesday the 28th of July 2015