Recognizing mouse and keyboard inputs within an Angular application when using ng-repeat

In my application, I am dynamically generating a series of spans using ng-repeat, with each span having a unique id (e.g. span-{{$index}}). Now, I am looking to implement the following functionality:

  • When clicking on a span, I want to copy the id of that span, which I have achieved through ng-click.
  • I aim to enhance this feature by detecting multiple clicks in order to create an array of selected ids, but only if the CTRL key is pressed during those clicks.

For example, if I hold down the CTRL key while selecting spans with ids 1, 3, 5, and 7, the resulting array should be [1, 3, 5, 7]. However, if CTRL is not held down, then only the last selected span's id should be captured (i.e. [7]).

Is it possible to bind events relatively? For instance, if I select span with id 1 and press CTRL+DOWN_ARROW, id 2 should also be selected, followed by id 3 upon subsequent presses of DOWN_ARROW.

The closest reference I can find to this type of user experience is in Gmail when composing a new email and selecting contacts. It allows for various keyboard and mouse combinations for selection, much like what I am trying to achieve here.

I am experimenting with different UX techniques but need guidance on how to implement this in Angular specifically.

Answer №1

To find the answer to your initial query, refer to the plunkr provided below.

If you include $event in your ng-click function, you can retrieve the event in your controller. In my demonstration, I verified if altKey was true, indicating whether the alt key was pressed simultaneously with the click. Additionally, ctrlKey, shiftKey, and the specific mouse button pressed are accessible. Refer to the MouseEvent object documentation here - http://www.w3schools.com/jsref/dom_obj_event.asp

The controller setup is as follows:

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

If the logic starts getting more intricate, employing a directive would be advisable.

For addressing the second question, foundational components are exhibited in the proceeding 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 are monitoring key presses on the document and rechecking for altKey. Subsequently, if the keyCode corresponds to our defined hotkeys, we forward a signal to $rootScope using $rootScope.$broadcast(), which the controller listens to via $rootScope.$on().

In this scenario, pressing alt+s will append additional ids, whereas alt+a will reduce them back to the initially selected one.

Answer №2

If you're looking to capture meta key information in Angular, consider using a custom directive. Take a look at this example showcasing how you can achieve this and access the data within 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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The JavaScript "sort()" method outlined in the Mozilla Documentation specifically created for the sorting of numbers

When it comes to sorting numbers in JavaScript, we can utilize the sort() function with a specific trick that yields perfect results. The tip for successful number sorting is as follows: [12, 2, 23, 3, 43, 54].sort(function (a, b) { return a - b ; } ) S ...

Alert message in jQuery validation for the chosen option value

I am attempting to validate a combo box with the code provided below. Currently, I receive multiple alert messages even if one condition is true. My goal is to only display one alert message when a condition is met and highlight the other values in red. Th ...

Modifying the height of the bar in Google Charts Timeline using react-google-charts

I am currently working on a Google Chart timeline using react-google-charts. <Chart chartType="Timeline" data={data} width="100%" options={{ allowHtml: true bar: { groupWidth: 10 }, }} ...

Sending a variable to a VueJS component

I'm looking to pass a variable down to a component in my current setup. Here's the structure: Main: Meet.vue <html> <div class="carousel-cell"> <Category :searchTerm="woman"></Category> </div> <div cla ...

What is the best way to utilize "exports" in package.json for TypeScript and nested submodules?

Looking to leverage the relatively new "exports" functionality in Node.js/package.json for the following setup: "exports": { ".": "./dist/index.js", "./foo": "./dist/path/to/foo.js" } so that ...

Using a template literal as a prop is causing rendering issues

I have a functional component const CustomParagraph = forwardRef((ref: any) => { return ( <div> <p dangerouslySetInnerHTML={{ __html: props.text }}></p> </div> ); }); Whenever I use this component, I am unable ...

Maintaining microsecond accuracy when transferring datetime values between Django and JavaScript

It appears that django, or the sqlite database, is saving datetimes with microsecond precision. However, when it comes to transferring a time to javascript, the Date object only works with milliseconds: var stringFromDjango = "2015-08-01 01:24:58.520124+1 ...

Problem with TypeScript involving parameter destructuring and null coalescing

When using parameter destructuring with null coalescing in TypeScript, there seems to be an issue with the optional name attribute. I prefer not to modify the original code like this: const name = data?.resource?.name ?? [] just to appease TypeScript. How ...

Implement input validation in React by enhancing the functionality of HTML input tags

Below is the input provided: const REGEX_EMAIL_VALIDATION = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}&bsol ...

Redux state not reflecting changes until second click

My redux store has a simple boolean setup to track whether a sidebar is expanded or not. However, I'm encountering an issue where, even though the default value is false, clicking the toggle button outputs false first. Ideally, if it's initially ...

.htaccess file is causing js and css files to not load

I followed an MVC tutorial by howcode on YouTube, but I encountered an issue where my CSS and JS files were not loading due to the htaccess configuration. .htaccess file: RewriteEngine On RewriteRule ^([^/]+)/? index.php?url=$1 [L,QSA] I attempted vario ...

Tips for sending a PHP JSON array to a JavaScript function using the onclick event

I am trying to pass a PHP JSON array into a JavaScript function when an onclick event occurs. Here is the structure of the PHP array before being encoded as JSON: Array ( [group_id] => 307378872724184 [cir_id] => 221 ) After encoding the a ...

When using the jQuery ajax function to validate a form, it is important to note that the $_POST variables

I have an HTML form along with a jQuery function for form validation. After submitting the form values to my PHP files, I notice that the $_POST variable is not being set. What could be causing this issue? <form id="signup" class="dialog-form" action= ...

The onChange event seems to be failing to activate during a jQuery / Ajax form submission

Differences in Form Submission Methods The onChange event functions correctly with the traditional Type and Action method in both Firefox and Chrome. <form name="frmname" action="./add_p.php" method="POST"> <div> <select name=" ...

Adding wrapAll in jQuery or PHP after tags with identical IDs can be achieved by selecting all the target elements

web development <?php foreach ($forlop as $value) : ?> <?php $stringTitle = substr($value->getTitle(), 0, 1); ?> <?php if(is_numeric($stringTitle)){ echo "<h3 id ...

Tips for creating a responsive carousel slider for images

No matter how much I've tried, I can't seem to find a solution on how to make my image responsive along with the caption. Below is my HTML code: <section id="banner"> <div class="banner-bg"> <div class="banner-bg-item ...

Using jQuery and PHP to send a dynamic form through AJAX

I'm currently working on a pet registration form where users can add new pets. When a user clicks the "add pet" button, I use jQuery to clone the pet section of the form and give each cloned section an id like #pet-2, #pet-3, and so on. Although my ...

"Learn the technique of adding a new data attribute before every element in a step-by-step

I am currently working with the following HTML code: <div id="elem"> <div data-foo="aaa"></div> <div data-foo="aaa"></div> <div data-foo="aaa"></div> <div data-foo="bbb"></div> < ...

The background image causes the scrollbar to vanish

As a beginner, I am in the process of creating a web page that features a consistent background image. However, I have encountered an issue where the scroll bar does not appear on a specific page called "family details" due to the background image. I atte ...

Guide to positioning a div in the center while implementing animations through transition and transformation using scale

Creating a popup for my React app without relying on external libraries is my current project. I am experimenting with using transition and transform with scale to size the popup dynamically based on screen size and content, then center it on the screen. ...