Reactive forms in Angular now support changing focus when the Enter key is pressed

I have successfully created a table and a button that generates dynamic rows with inputs inside the table. One issue I'm facing is that when I press enter in the first input, a new row is created (which works), but I can't seem to focus on the new input field. Below is my current implementation:

<input type="text" class="form-control" placeholder="Product Code" formControlName="product_code" tabindex="{{i+1}}" (keyup.enter)="autoProduct($event)">

Here is the relevant code from my .ts file:

autoProduct(event) {
    this.addProduct();
    if (event.keyCode === 13) {
      event.preventDefault();
      const inputs =
        Array.prototype.slice.call(document.querySelectorAll('input'));
      console.log(inputs);
      const index =
        (inputs.indexOf(document.activeElement) + 1) % inputs.length;
      console.log(index);
      const input = inputs[index];
      console.log(input);
      input.focus();
      input.select();
    }
  }

I've looked at solutions on Stack Overflow, but I haven't been able to get it to work. Any assistance would be greatly appreciated.

Answer №1

You can implement the ViewChildren functionality.

private inputToFocus: any;
@ViewChildren('inputToFocus') set inputF(inputF: any) {
  this.inputToFocus = inputF
  this.inputToFocus.first.nativeElement.focus();
}

To use this, add #inputToFocus in your input tag. For example: <input ... #inputToFocus>

Edit

If you want to add a new input field dynamically, here is the code snippet:

.ts:

import { Component, ViewChildren } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular 6';
  counts = [1];
  private inputToFocus: any;
  @ViewChildren('inputToFocus') set inputF(inputF: any) {
    this.inputToFocus = inputF
    this.inputToFocus.last.nativeElement.focus();
  }

  autoProduct(event) {
    if (event.keyCode === 13) {
      event.preventDefault();
      const inputs =
        Array.prototype.slice.call(document.querySelectorAll('input'));
      const index =
        (inputs.indexOf(document.activeElement) + 1) % inputs.length;
      this.addProduct(index);
      const input = inputs[index];
      input.focus();
      input.select();
    }
  }
  addProduct(i) {
     this.counts.push(i)
  }
}

.html:

<div *ngFor="let count of counts; let i=index">
  <input type="text" class="form-control" placeholder="Product Code" tabindex="{{i+1}}" (keyup.enter)="autoProduct($event)" #inputToFocus>
</div>

Please note that I have updated the usage of .last.

Answer №2

Here is a code snippet that allows you to have control over focus in a form. This code focuses on the next field every time you press enter or the arrow down key, and it can be customized according to your needs. It also works seamlessly with Bootstrap.

The code records input fields in a table, giving you the flexibility to enable focus on any specific field. If you dynamically add an input field, the table will automatically update.

In my experience, I haven't found a better solution using Angular.

To implement this functionality, you can use the following HTML code in your editor component:

<div>
    <form>
      <div class="container-fluid" *ngFor="let item of data; let i = index">
        <div class="form-group">
          <div class="row">
            <div class="col-md-3">{{item.designation}}</div>
            <div class="col-md-2">{{item.type}}</div>
            
            <div *ngIf="item.type == 'float'" class="col-md-2">{{item.value | number: '1.1-3'}}</div>
            <div *ngIf="item.type == 'int'" class="col-md-2">{{item.value | number}}</div>

            <div class="col-md-2">
              <input #input type="number" class="form-control" (keydown)="onKeydown($event, i)">
            </div>

            <div class="col-md-3">{{item.commentaire}}</div>
          </div>
        </div>
      </div>
    </form>
  </div>

In the editor component TypeScript file (editor.component.ts), incorporate the following logic:

import { Component, OnInit } from '@angular/core';
import { ViewChildren, QueryList } from '@angular/core';

@Component({
  selector: 'app-editor',
  templateUrl: './editor.component.html',
  styleUrls: ['./editor.component.css']
})
export class EditorComponent implements AfterViewInit {

  @ViewChildren("input") inputs: QueryList<any>

  constructor() {
  }

  private onKeydown(event, val) {
    console.log(event.key);
    
    if (event.key === "Enter" || event.key === "ArrowDown") {
      // Focus on the next input field
      if (val + 1 < this.inputs.toArray().length) {
        this.inputs.toArray()[val + 1].nativeElement.focus();
      } else {
        this.inputs.toArray()[0].nativeElement.focus();
      }
    }
  }

  private processChildren(): void {
    console.log('Processing children. Count:', this.inputs.toArray().length)
  }

  ngAfterViewInit() {
    console.log("AfterViewInit");
    console.log(this.inputs);
    this.inputs.forEach(input => console.log(input));

    this.inputs.changes.subscribe(_ => 
      this.processChildren()
    );
  }

}

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

Learn the process of updating a nested document within an array in MongoDB

I have a data structure as shown below: { "name":"xxxxxx", "list":[ { "listname":"XXXXX1", "card":[ { "title":"xxxxxx", "descip":"xxxxxxx ...

Rendering components asynchronously in ReactJS

After completing my ajax request, I need to render my component. Here is a snippet of the code: var CategoriesSetup = React.createClass({ render: function(){ var rows = []; $.get('http://foobar.io/api/v1/listings/categories/&apo ...

Is it possible in Typescript to reference type variables within another type variable?

Currently, I am working with two generic types - Client<T> and MockClient<T>. Now, I want to introduce a third generic type called Mocked<C extends Client>. This new type should be a specialized version of MockClient that corresponds to a ...

Setting the default selection in AngularJS based on the URL entered

I've encountered an issue with a dropdown menu in my AngularJS version 1.4 application. The dropdown menu contains links to different sections of the page. The problem arises when I directly enter the page URL - instead of selecting the correct link f ...

Whenever I attempt to host my Node.js app using the GCP deploy command, it fails to work properly. The error message that appears states: "Module 'express' cannot be found."

My NodeJS application is written in TypeScript and utilizes the Express framework. I'm looking to host it on the GCP cloud using the gcloud app deploy command. First, I compile my TS sources to JavaScript - is this the correct approach? Afterwards, I ...

How can I change a PHP for loop to Javascript?

Can the following code be converted to JavaScript? for (let lift of liftDetails) { document.write('<option>'+ lift["LiftMakes"] +'</option>'); } ...

What could be causing my AngularJS JSONP request to fail when trying to query Solr?

After attempting to query my Solr server with the provided code snippet: var url ="http://localhost:8080/solr/sdc/selectwt=json&callback=JSON_CALLBACK&q=opioid" $http.jsonp(url ).success(function(res){ console.log(res) }) An error is returned ...

What is the best way to connect a toArray function to an interface property?

Consider the following scenario: interface D { bar: string } interface B { C: Record<string, D> // ... additional properties here } const example: B = { C: { greeting: { bar: "hi" } } // ... additional properties here } Now I would like t ...

Is there a way for me to identify when I am "traveling" along the same path?

I want to create a toggle effect where a view is hidden if the user tries to revisit it. This can be useful for showing/hiding modal boxes. Here's the code I attempted: /* Root Instance */ const app = new Vue({ router, watch: { '$route&a ...

Bringing together projects utilizing varying Typescript versions within Visual Studio 2015

When working with VS2015-SP2, imagine a solution that contains two typescript projects. One project is using version 1.5 and the other is using version 1.7. How will the compiler handle this situation? ...

Shifting an element to the right before revealing or concealing it with Jquery Show/Hide

$(document).ready(function(){ var speed = 700; var pause = 3500; function removeFirstElement(){ $('ul#newsfeed li:first').hide('slide', {direction: "up"}, speed, function() {addLastElement(thi ...

Reference ngFor for Input Validation Template

I'm currently facing an issue with validating input fields within a *ngFor loop. I am struggling to create unique template references for each input field. Basically, I need all input fields to be required on submit unless at least one of them is fill ...

Issue with displaying and hiding list elements using jQuery

I am attempting to create an accordion feature using <li> elements with classes .level1, .level2, .level3, and so on. The problem I am encountering is that when I click on a .level2 element, the items hide correctly until the next .level2 element wit ...

The ngOnChanges lifecycle hook is triggered only once upon initial rendering

While working with @Input() data coming from the parent component, I am utilizing ngOnChanges to detect any changes. However, it seems that the method only triggers once. Even though the current value is updated, the previous value remains undefined. Below ...

Requesting data asynchronously using AJAX and displaying the filtered results on a webpage using JSON

When I send a request to my node.js server for a .json file containing person information (first name, last name), I want the data to be filtered based on user input. For example: When I request the .json file from the server, it gives me a list of people ...

Embed a static label inside an input field that remains constant even while text is inputted, without using a placeholder. Crafted using HTML,

Take a look at the screenshot below - what you see on the left side is my current setup, while on the right side is the desired outcome achieved without any plugins or HTML5 attributes The left side scenario occurs when I have 2 input fields - one with th ...

Encountering a problem while attempting to compile an Angular 8 application using the "ng build" command

Error Log Below: An error occurs while the application is running with ng-serve, but ng build throws a different error. Generating ES5 bundles for differential loading... Browserslist: caniuse-lite is outdated. Please run the following command npm u ...

Maintaining AngularJS Authentication Securengular: Ensuring

I need to find the ideal architectural solution. Below is the HTML code I currently have: <body ng-controller="individualFootprintController as $ctrl"> <div ng-hide="$ctrl.authenticated"> <h1>Login</h1> Wit ...

How does assigning a checkbox's value as 'undefined' result in the addition of ng-invalid?

I'm facing an issue with a checkbox in my Angular project. The checkbox has a false value of undefined, and even though it's not marked as required, the form doesn't validate when I check and uncheck it. This is because the class ng-invalid ...

Google Maps API now offers the ability to generate directions with up to 500 waypoints

I am facing a challenge with displaying a route on Google Maps using an array of 500 waypoints extracted from a GPS route. Google Maps is unable to create a direction or route with more than 23 waypoints, making it difficult to replicate the original GPS ...