Little Johnny Angular Has Trouble Focusing in Class

Short post this week, but working on a longer one in the next couple weeks regarding Google’s new Puppeteer project.  Spoiler- I think it’s pretty cool.

I have worked with latest generation angular for a couple years now.  It’s generally great, occasionally frustrating, and often interesting.  However, until this past week, I hadn’t really had a need to work with directives.  Specifically, attribute directives, but it turns out they can be very useful!

The challenge: I was creating a search feature for a new website.  I had the actual search function working well (and the data being searched over was small enough to include in an in-memory JSON structure, so it’s a nice and fast search as you type setup).  All that was left was to put a UI on this thing.  I put together a nice full screen display with large input element that fires the search function as a user types.  It will show/hide based on an ngIf conditional.  All simple enough in Angular land- and something we do all the time (by the way, I also tried this with the [hidden] element attribute, but ran into the same difficulty below).

So, click the search icon, the background fades in and search input slides down.  The user can search and results pop right up.  All great- but the input field autofocus was not cooperating.  It would fire properly the very first time ngIf became true, but never again after that.  If a user closed the search display, then opened again for another search, no autofocus.

Not a huge deal- but an inconvenience for users, and something that I should be able to make work.  It makes sense- the built in autofocus attribute was probably only ever designed to fire on a page load- but that only happens once (ideally) with an angular application.  I tried firing a .focus() event in my controller, but it didn’t seem to have any effect.

The answer was a directive.  Specifically, an attribute directive.  Directives were all over angular V1, but in latest generation, you can usually get away with just having components and services.  In this case, I could just make a super simple directive that grabs a reference to the element (the angular way!) and fires the .focus() in the right lifecycle hook (some references said it would work in onInit, but I had to use afterViewInit).

import { AfterViewInit, Directive, ElementRef } from '@angular/core';
@Directive({ selector: '[ifautofocus]' })
export class IfAutofocus implements AfterViewInit {
constructor(private elementRef: ElementRef) {}
ngAfterViewInit() {
remember to include it in your module's 'declarations' array,
then import it into your component.
add it like you would the 'autofocus' tag in your template:
<input formControlName="searchTerm" type="text" placeholder="Search!" ifautofocus />

Boom- the search input element gets focused every time the search display opens!