Skip to content

Latest commit

 

History

History
109 lines (79 loc) · 4.33 KB

README.md

File metadata and controls

109 lines (79 loc) · 4.33 KB

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.