I have an app in which I generate a set of spans using ng-repeat, and each span has a unique id (let's say span-{{$index}}
). Now I want to perform the following:
For eg. if I had the ctrl button clicked when I chose span with id 1,3,5,7, my array should have [1,3,5,7] , but if I didn't have the CTRL key pressed then I should only have [7], as it was the last span selected.
Also, can I bind relative events? E.g. if I select span with an id of 1, if I click CTRL+DOWN_ARROW, id 2 is also selected... and then id 3 and so on until I keep pressing DOWN_ARROW.
I guess the closest I've seen of this type of UX is with selecting contacts in Gmail while composing a new mail. I can select contacts using all sorts of keyboard and mouse combinations. I'm looking for something very similar
I'm playing around with different UX techniques but I'm stuck on how exactly I could do this with angular.
For your first question see the plunkr below.
If you pass $event through to your ng-click function you can access the event in your controller. In my example I checked if altKey was true which is checking if the alt key was pressed at the same time as the click. You can also access ctrlKey, shiftKey and which mouse button was pressed. See MouseEvent object here - http://www.w3schools.com/jsref/dom_obj_event.asp
The controller:
angular.module('exampleApp', [])
.controller("ItemCtrl", function($scope){
$scope.items = [
{text: "Bob", id: 1},
{text: "Alice", id: 2},
{text: "Frank", id: 3},
{text: "Lisa", id: 4}
];
$scope.itemList = [];
$scope.addItemIdToList = function(event, item){
if(event.altKey){
if(isItemInList(item)){
removeItemIdFromList(item);
} else {
addItemIdToList(item);
}
} else {
addItemIdAsSingleSelection(item);
}
};
var isItemInList = function(item){
var indexOfItem = $scope.itemList.indexOf(item.id);
return indexOfItem > -1;
}
var removeItemIdFromList = function(item){
var indexOfItem = $scope.itemList.indexOf(item.id);
$scope.itemList.splice(indexOfItem, 1);
};
var addItemIdToList = function(item){
$scope.itemList.push(item.id);
};
var addItemIdAsSingleSelection = function(item){
$scope.itemList = [item.id];
};
})
http://plnkr.co/edit/RAX5oxkTomXxryp0sNNc
When the logic starts to become a bit more complicated it would probably be best to do this sort of thing in a directive.
For the second question the basic parts can be seen in the following example:
angular.module('exampleApp', [])
.directive('keypressEvents', function ($document, $rootScope) {
return {
restrict: 'E',
link: function () {
console.log('linked');
$document.on('keypress', function(e) {
if(e.altKey){
var s = 223;
var a = 229;
if(e.which == s){
$rootScope.$broadcast("add_next_id");
} else if(e.which == a){
$rootScope.$broadcast("remove_last_id");
}
}
})
}
}
})
.controller("ItemCtrl", function($scope, $rootScope){
$scope.items = [
{text: "Bob", id: 1},
{text: "Alice", id: 2},
{text: "Frank", id: 3},
{text: "Lisa", id: 4}
];
$scope.itemList = [1];
$rootScope.$on('add_next_id', function (evt, obj, key) {
$scope.$apply(function () {
addNextId();
});
});
$rootScope.$on('remove_last_id', function (evt, obj, key) {
$scope.$apply(function () {
removeLastId();
});
});
var addNextId = function(){
var lastId = $scope.itemList[$scope.itemList.length - 1];
if(lastId < $scope.items.length){
$scope.itemList.push(lastId+1);
}
};
var removeLastId = function(){
if($scope.itemList.length > 1){
$scope.itemList.pop();
}
};
$scope.isItemInList = function(item){
var indexOfItem = $scope.itemList.indexOf(item.id);
return indexOfItem > -1;
}
})
http://plnkr.co/edit/PyyjfRMovygeq9qNbzWo
We listen on the document for key presses and check again for altKey. Then if the keyCode is one of our hotkeys we send a message to $rootScope using $rootScope.$broadcast() which the controller is listening to with the $rootScope.$on() method.
In the above example alt+s will add more ids and alt+a will remove them down to the originally selected one.
Perhaps an Angular directive would be helpful. Here's an example of how you can capture meta key info using an angular directive and get access to the info inside an Angular Controller (Plnkr):
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body ng-app="myapp" ng-controller="main">
<h1>Hello {{person}}</h1>
<p>Ctrl: |{{info.ctrl}}|</p>
<keyboard info="info"></keyboard>
<script>
var app = angular.module('myapp', []);
app.controller('main', function($scope){
$scope.info = { ctrl: false };
$scope.person = "Me";
});
app.directive('keyboard', function($timeout){
return {
scope: {
info: '='
},
link: function(scope, element, attr){
console.dir(scope.info);
$(document).on('keydown', function(e){
$timeout(function(){
scope.info.ctrl = e.ctrlKey;
});
});
$(document).on('keyup', function(e){
$timeout(function(){
scope.info.ctrl = e.ctrlKey;
});
});
}
}
});
</script>
</body>
</html>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With