What You Need to Know about Angular v13

Angular v13 has arrived! And with it come a lot of exciting new features and updates. Angular continues to improve runtime performance, decrease compilation time, promote good software development practices, enhance developer experience, and keep up to date with dependencies such as TypeScript and RxJS. Is anyone else excited about RxJS v7?! 🤩 Let’s take a look at a few of the many new exciting features in Angular v13 with some code examples using authentication.

Table of Contents

So long, View Engine!

With v13, View Engine is no longer available, replaced by Ivy. Ivy is the future of Angular applications, and the benefits are tremendous. After initially landing in v12, Ivy paves the way for new feature updates, simplifies existing capabilities, and increases rendering performance.

The way you can now create components dynamically is an example of how this release simplifies existing capabilities. Dynamic components are components loaded at runtime. You might use this when you need to tailor visible components based on responses from a server call. Previously, to dynamically create components, you had to use the ComponentFactoryResolver. Now the API takes the Component type directly. Let’s look at how this works.

Set up the Authorization Server

In my example, I am authenticating using OAuth 2.0 with OpenID Connect through Okta. In my Okta Authorization Server, I added a custom claim named pet_preference to my identity token. Does this sound only vaguely familiar? Refresh your understanding of OAuth 2.0 and OpenID Connect by reading “The Things to Keep in Mind about Auth”.

With this custom claim, I want to display dynamic components specific to the value. The app uses the claim value to rotate through images of pets that match their preference.

Prepare the components

To write something like this, you’ll first create components for the customized views of different pets that all implement the same interface, such as one named PreferenceComponentInterface. The interface has a property named data so you can pass in customized information. You’ll also need to get the pet_preference custom claim value and retrieve content specifically for it. Once you have the data for the preferred pet, you can add the code to create dynamic components.

Implement the dynamic component creation

Create a Directive to house the view.

import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appPreference]'
})

export class PreferenceDirective {
  constructor(public viewContainerRef: ViewContainerRef) { }
}

And a container component that handles the dynamic creation of the component. I simplified the code snipped to focus on the v13 change. In an upcoming post, I’ll do a complete walkthrough of creating this application.

class PreferenceItem {
  component: Type<PreferenceComponentInterface>;
  info: any;
}

@Component({
  selector: 'app-secret-preference',
  template: `<ng-template appPreference></ng-template>`
 })

export class SecretPreferenceComponent implements OnInit {
  @ViewChild(PreferenceDirective, {static: true}) private host!: PreferenceDirective;
  
  private preferences: PreferenceItem[] = [{
    component: MyCustomComponent,
    info: 'example'
  }, {
    component: MyOtherCustomComponent,
    info: {
      isTrue: true
    }
  }];
  
  public ngOnInit(): void {
    const preferredItem = this.preferences[0];
    const compRef = this.host.viewContainerRef.createComponent<PreferenceComponentInterface>(preferredItem);
    compRef.instance.data = preferredItem.info;
  }
}

Notice you didn’t have to inject the ComponentFactoryResolver to do this. The API is more straightforward to use. A more realistic use case might be a custom claim for the department and displaying customized content based on the authenticated user’s department.

Clean-up after each test

Testing Angular apps is much improved in v13, and better cleanup of the DOM between tests is the new default. Now, Angular does a better job of cleaning up the DOM, and tests run faster and more performantly with better isolation between tests.

The clean-up behavior is configurable when configuring or resetting the TestBed. Let’s look at an example test where we greet the user after they’ve logged in.

Component code

@Component({
  selector: 'app-profile',
  template: `
    <ng-container *ngIf="name$ | async as name ">
      <span>Welcome {{name}}!</span>
    </ng-container>
  `
})

export class ProfileComponent {
  public name$: Observable<string> = this._authStateService.authState$.pipe(
    filter((s: AuthState) => !!s && !!s.isAuthenticated),
    map((s: AuthState) => s.idToken?.claims.name ?? 'stranger')
  );

  constructor(private _authStateService: OktaAuthStateService) { }
}

Test code

describe('ProfileComponent', () => {
  let component: ProfileComponent;
  let fixture: ComponentFixture<ProfileComponent>;

  let authStateSpy = jasmine.createSpyObj<OktaAuthStateService>([], { authState$: of(authState) });

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [ ProfileComponent ],
      providers: [
        { provide: OktaAuthStateService, useValue: authStateSpy }
      ],
      teardown: { destroyAfterEach: false } // flakey tests!
    });
  });

  it('should show text that welcomes the user by name', () => {
    fixture = TestBed.createComponent(ProfileComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
      
    const spanEl = fixture.debugElement.query(By.css('span'));
    expect(spanEl).toBeTruthy();
    expect(spanEl.nativeElement.innerHTML).toEqual('Welcome Test Name!');
  });

  it('should show text that welcomes a user with no name', () => {
    (Object.getOwnPropertyDescriptor(authStateSpy, 'authState$')?.get as jasmine.Spy).and.returnValue(of({
      isAuthenticated: true,
      idToken: {...idToken, claims: {sub: 'sub'}}
    }));
      
    fixture = TestBed.createComponent(ProfileComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();

    const spanEl = fixture.debugElement.query(By.css('span'));
    expect(spanEl).toBeTruthy();
    expect(spanEl.nativeElement.innerHTML).toEqual('Welcome stranger!');
  });
});

We can configure the teardown cleanup in this test suite by changing the value of destroyAfterEach. With this change enabled by default, you have the option of writing new tests with better performance. Plus, you can disable the default for tests that aren’t ready to consume the changes. Angular has our backs on non-breaking updates!

Enhanced developer tooling

Creating Angular apps is now easier with developer tooling enhancements and compilation time improvements.

The first thing you might notice is how much faster the build time is. A lot of work went into improving the build time. By adding a build cache, the Angular team found build time improvements of up to 65+%!

The Angular Language Service’s tooling improvement to auto-apply optional chaining feels like a small thing but is such an appreciated feature. I can focus on the object property I want to use, and the tooling handles the optional chaining for me!

Auto applying optional chaining in VS Code for a deep object with optional properties

Note: The example demo shown above is for demonstration purposes, and exaggerates capabilities to showcase the new feature. Please remember to apply sound software development practices to your real-world applications.

So long, Internet Explorer!

In this release, we also say goodbye to Internet Explorer. Dropping Internet Explorer support means lots of doors open up for new features, refactoring the code base, and keeping up with security best practices. With extra polyfills, you can use Okta’s Auth JS library in Internet Explorer, but the recommendation is to migrate away from it.

All the Angular v13 details

These are the features that I found most interesting, but there are lots more in Angular v13! You can read more about them in the Angular team’s blog post. You can read about the changes in the new version of TypeScript and RxJS.

Upcoming changes

Angular keeps improving and growing. The subsequent releases should prove exciting, with features such as strict typing for forms and standalone components in the works.

If you’re interested in Angular content, check out the following posts

Don’t forget to follow us on Twitter and subscribe to our YouTube channel for more great content. What are your favorite Angular v13 features, or what updates are you looking forward to the most? Feel free to drop it in the comments below, as well as any questions or requests for tutorials you’d like to see next.

Alisa Duncan is a Senior Developer Advocate at Okta, a full-stack developer, and a community builder who loves the thrill of learning new things. She is a Google Developer Expert in Angular and organizes coding workshops and community events locally and internationally. Her background is primarily working on enterprise software platforms, and she is a fan of all things TypeScript and JavaScript.

Okta Developer Blog Comment Policy

We welcome relevant and respectful comments. Off-topic comments may be removed.