Reputation: 8695
I've got a simple TODO application (from Apress book, Pro Angular). Currently I've got a little application where the user types some information into a box, clicks a button and a TODO task pops up onto the screen. What I would like to have happen is after the user clicks on the button to add the task to the page, then the focus goes to the input text box again. What I have currently works, but I would like to have this as a directive so I can reuse it.
JS
var model = {
user: "Adam"
}
var todoApp = angular.module('todoApp',[]);
//get data
todoApp.run(function($http){
$http.get('todo.json').success(function(data){
model.items = data;
});
});
//need a directive that can listen for a button click
todoApp.directive('refocus',function(){
return {
restrict: 'a',
link: function(scope, elem, attrs){
scope.$watch('someEvent',function(){
//how to listen for a specific click event
//and return focus to the input element afterwards
})
}
}
})
todoApp.filter('checkedItems',function(){
return function(items,showComplete){
var resultArr=[];
angular.forEach(items,function(item){
if(item.done==false || showComplete ==true){
resultArr.push(item);
}
})
return resultArr;
}
})
todoApp.controller('ToDoCtrl',function($scope){
$scope.todo = model;
$scope.incompleteCount = function(){
var count =0;
angular.forEach($scope.todo.items,function(item){
if(!item.done){
count++;
}
});
return count;
}
$scope.addNewItem = function(actionText){
$scope.todo.items.push({action: actionText, done: false});
$scope.actionText = "";
$scope.returnFocus('#getFocus');
};
$scope.returnFocus = function(elem){
$(elem).focus();
};
});
HTML
<body ng-controller="ToDoCtrl">
<div class="page-header">
<h1>
{{todo.user}}'s To Do List
<span class="label label-default">
</span>
</h1>
</div>
<div class="panel">
<div class="input-group">
<input id="getFocus" ng-model="actionText" class="form-control" ng-focus="" />
<span class="input-group-btn">
<button ng-click="addNewItem(actionText)" class="btn btn-default">Add</button>
</span>
</div>
<table class="table table-striped">
<thead>
<tr>
<th>Description</th>
<th>Done</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in todo.items | checkedItems: showComplete | orderBy:'done'">
<td>{{item.action}}</td>
<td><input type="checkbox" ng-model="item.done"/></td>
</tr>
</tbody>
</table>
<div class="checkbox-inline">
<label><input type="checkbox" ng-model="showComplete">Show complete</label>
</div>
</div>
</body>
You can see in the addNewItem function that I use a jQuery selector to return focus to the input text, but this doesn't make it reusable. How can I finish my stubbed out directive to make this type of behavior reusable?
Upvotes: 3
Views: 329
Reputation: 13686
There are a couple of modules that do this. (Shameless Plug!) Here's one: angular-focus-on
My approach is through the use of events. It's pretty straight forward and simple. Here is a fiddle with the module implemented.
A quick view of the lines I changed:
First add the module to your app:
var todoApp = angular.module('todoApp',['kf.focusOn']);
Then we use it by adding the focus-on
, and event="todoAdded"
attributes. So when a todoAdded
event is fired this element will be focused.
<input ng-model="actionText" class="form-control" focus-on event="todoAdded" />
Now in the controller all we have to do is $scope.$broadcast('todoAdded')
in order to fire off a todoAdded
event. Which looks like:
$scope.addNewItem = function(actionText){
$scope.$broadcast('todoAdded'); // this fires an event.
$scope.todo.items.push({action: actionText, done: false});
$scope.actionText = "";
};
Now let's take a look at how the module works:
angular.module('kf.focusOn', [])
.directive('focusOn', [function() {
return {
restrict: 'A', // Restrict to attribute only
scope: {
event: '@' // Accept an event attribute.
},
link: function($scope, elem) {
$scope.$on($scope.event, function() { // On the event passed by $scope.event...
elem[0].focus(); // Focus on the element.
});
}
}
}]);
as you can see it's nothing fancy, and super simple, it accepts an event
scope and just applies focus to the element when the event is triggered.
Upvotes: 2