Skip to content

An Angular directive that allows you to control focus including autofocus-like functionality

License

Notifications You must be signed in to change notification settings

DeanPDX/angular-input-focus

Repository files navigation

Angular Input Focus Attribute Directive

This package is for handling focus on html elements in Angular apps. It is tightly coupled with the DOM but safe to use in server-side rendering settings since we are checking to make sure the directive is running in a browser before using any DOM-specific functions.

NPM Build Status Test Status Code Coverage Issues License

Installation

Install using NPM:

npm install angular-input-focus --save

Next, import the module in your application module:

import { AngularInputFocusModule } from 'angular-input-focus';

@NgModule({
  imports: [AngularInputFocusModule]
})

Now you're ready to use the directive in your project.

Usage

Here are some standard use cases.

Autofocus

For autofocus-like functionality, you can set libFocus to true (or a condition):

<!-- Focus First name when control is rendered -->
First name: <input type="text" name="fname" [libFocus]="true">
Last name: <input type="text" name="lname">

Focus using an EventEmitter

You can also pass an EventEmitter<boolean> to the setFocus input. Imagine a component called MyComponent:

export class MyComponent {
    // We will pass this to the directive in our view
    focusEvent = new EventEmitter<boolean>();
    // When called, will set the focus on our input
    setFocus() {
        this.focusEvent.emit(true);
    }
}

In the template for MyComponent:

<input [libFocus]="false" [setFocus]="focusEvent">`

Whenever your focusEvent emits a value, your element will focus/blur depending on whether the emitted value is true or false. You can find a working example of this in the tester app for the project.

Focus last element with dynamic elements

You don't need to use EventEmitter for this. Simply set libFocus to a conditional boolean value:

rows = ['First', 'Second'];

addRow() {
  this.rows.push('');
}

shouldFocusRow(index: number): boolean {
  return index + 1 === this.rows.length;
}

trackByIndex(index, row) {
  return index;
}

And in your template:

<button (click)="addRow()">Add row</button>

<!-- Important to use trackBy to prevent stuttering on input. -->
<div *ngFor="let row of this.rows; let i = index; trackBy: trackByIndex">
  <input id="row{{ i }}" [libFocus]="shouldFocusRow(i)" [(ngModel)]="rows[i]" />
</div>

It's important in general to use trackBy for dynamic inputs to avoid UI stutter as you're typing. Here's a working StackBlitz example you can run and modify.

Note on skipChangeDetection

If you're using Angular Material, Change Detection needs to run after setting focus because Angular Material tracks focus; otherwise you will get the dreaded ExpressionChangedAfterItHasBeenCheckedError exception. If you are using native HTML inputs, you can skip change detection by setting [skipChangeDetection]="true".

Development

The main app (angular-input-focus-tester) is for testing the angular-input-focus library in the projects folder. Run ng serve to build and serve the test app.

To publish a new version of the library to NPM, run npm run publish-lib. This will do the following:

  • Run npm version patch to create a new patch.
  • Build the library.
  • Copy readme/license from the main project to the library.
  • Publish the patch on NPM.

About

An Angular directive that allows you to control focus including autofocus-like functionality

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published