2017-09-12

Implementing a really simple Elvis Operator in TypeScript

Here is a simple routine that implements what is known as the Elvis Operator in TypeScript.

In C# you can write code like this

Nullable<int> age = person?.BestFriend?.Mother?.CurrentHusband?.Age);

If any of the values along the way it will return a null rather than throwing a NullReferenceException.

Using the class in my previous blog Get a Lambda expression as a string it is possible to achieve the same in TypeScript using the following format

const age = elvisOperator(person, x => x.bestFriend.mother.currentHusband.age;

It doesn't currently support anything more than simple property access, so you can't access elements in an array for example.


import { Expression } from './expression';

export function isUndefinedOrNull(value: any): boolean {
  return _.isNull(value) || _.isUndefined(value);
}

export function elvisOperator(instance: TSource, member: (v: TSource) => TResult): any {
  let path = Expression.pathAsArray(member);
  let result = instance;
  do {
    if (!isUndefinedOrNull(result) && path.length > 0) {
      result = result[path[0]];
      path = path.slice(1);
    }
  } while (path.length > 0 && !isUndefinedOrNull(result));
  return result;
}

2017-09-01

A type safe way of creating Angular ReactiveForms and FormGroups

If, like myself, you prefer as many of your coding mistakes to be identified at compile time as possible then you might like the following example.

The FormBuilder in Angular expects us to identify our FormControls with a string name. If ever the API of your server changes then of course the names of those controls will also need to change. So, rather than using magic strings when building a FormGroup I wrote this small utility class for building them against a strongly typed class by using lambda expressions.

This routine uses a routine I blogged about recently ( Get lambda expression as a string)

Take the following interface as an example of something we wish to edit in a ReactiveForm.

interface Address {
    line1: string;
    line2: string;
    city: string;
}

The code to build the form would look like this
this.form = this.expressionFormBuilder
  .createFormGroup<Address>()
  .addFormControl(x => x.line1)
  .addFormControl(x => x.line2)
  .addFormControl(x => x.city)
  .build();

If you had a nested object like this
interface Person {
    name: string;
    address: Address;
}
interface Address {
    line1: string;
    line2: string;
    city: string;
}

Then you can also build your Reactive Form's sub-group in the same manner....
this.form = this.expressionFormBuilder
  .createFormGroup<Person>()
  .addFormControl(x => x.name)
  .addFormGroup(x => x.address, this.expressionFormBuilder
    .createFormGroup<Address>()
    .addFormControl(address => address.line1)
    .addFormControl(address => address.line2)
    .addFormControl(address => address.city)
    .build())
  .build();
There is some room for improvement, such as making the addFormGroup infer the type from the expression, but I'll leave that as an exercise for you to do, because I don't need it yet :)

Here is the code for the ExpressionFormBuild class. You can easily inject it into your component's constructor to get an instance, which you would then use in ngOnInit or in the component's constructor.

import { AsyncValidatorFn, FormArray, FormBuilder, FormGroup, ValidatorFn } from '@angular/forms';
import { Expression } from './expression';
import { Injectable } from '@angular/core';

/**
 * Builds reactive forms based on lambda expressions instead of string based names.
 */
@Injectable()
export class ExpressionFormBuilder {

  constructor(private formBuilder: FormBuilder) {}

  public createFormGroup<T>(): ExpressionFormBuilderState<T> {
    return new ExpressionFormBuilderState<T>(this.formBuilder);
  }
}

class ExpressionFormBuilderState<T> {
  private config = {};

  constructor(private formBuilder: FormBuilder) {}

  /**
   * Builds a FormGroup from the current state
   * @returns {FormGroup}
   */
  public build() {
    return this.formBuilder.group(this.config);
  }
  /**
   * Adds a form control for the specified name
   * @param {(t: T) => any} name A lambda expression identifying the member, e.g. x => x.firstName
   * @param {string} defaultValue The default value to give to the form control
   * @param {ValidatorFn} validator Optional validators to add to the FormControl
   * @param {AsyncValidatorFn} asyncValidator Optional async validators to add to the FormControl
   */
  public addFormControl(
    name: (t: T) => any,
    defaultValue?: string|null,
    validator?: ValidatorFn|null,
    asyncValidator?: AsyncValidatorFn|null
  ): ExpressionFormBuilderState<T> {
    const controlName = Expression.path<T>(name);
    this.config[controlName] = [defaultValue, validator, asyncValidator];
    return this;
  }

  /**
   * Adds a sub group
   * @param {string} name
   * @param group
   * @returns {ExpressionFormBuilderState}
   */
  public addGroup(name: (t: T) => any, group: any): ExpressionFormBuilderState<T> {
    const groupName = Expression.path<T>(name);
    this.config[groupName] = group;
    return this;
  }
}

2017-08-31

Failed to execute 'send' on 'XMLHttpRequest': Failed to load ng:///DynamicTestModule - Solved (Angular testing)

If when you run your tests you see an error similar to this

Failed to execute 'send' on 'XMLHttpRequest': Failed to load 'ng:///DynamicTestModule/xxxxxxComponent_Host.ngfactory.js

It means something in your component is throwing an exception and the test framework is returning a wrapped exception. To see the actual exception run ng test with -sm=false as a parameter

ng test -sm=false
This will not only stop your browser from freezing on that test, but will also give you the original error including line number.

2017-08-12

Angular - How to create a data aware custom component

Introduction

This blog will demonstrate how to create an Angular component that you are able to add [ngModel] [formControl] and [formControlName] attributes to your custom component, and have your component correct implement the features required to work with Angular forms.

Setting up the ngModule

First add FormsModule and ReactiveFormsModule to your main NgModule's import declaration
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Creating the custom component's template

Note: If you have installed @angular/cli using npm you can type ng g component /components/custom-input in a command prompt to create the component + template + test cases.
Next create a new component with the following html template
My custom input 
<input 
  (blur)="blurred()" 
  (focus)="focused()" 
  [(ngModel)]="value" />

The custom component's class code

First you need to import a few references
import { Component, forwardRef, Input } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
What these identifiers do:
  • NG_VALUE_ACCESSOR: A marker in the component's providers declaration to indicate that the new component implements ControlValueAccessor
  • ControlValueAccessor: The interface that needs to be implemented in order to support data-binding through [formControl] and [formControlName]
Now update the component's @Component declaration and add providers, and update the selector.
@Component({
  selector: '[formControl] custom-input, [formControlName] custom-input',
  templateUrl: './custom-input.component.html',
  styleUrls: ['./custom-input.component.css'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CustomInputComponent),
      multi: true
    }
  ]
})

And finally, the component's class code

export class CustomInputComponent implements ControlValueAccessor {
  private _value: any;

  private hasHadFocus = false;
  private hasNotifiedTouched = false;
  private propagateChange: any = () => {};
  private propogateTouched: any = () => {};

  public get value(): any {
    return this._value;
  }

  @Input('value')
  public set value(value: any) {
    this._value = value;
    this.propagateChange(value);
  }

  /**
   * Called when input (focus) is triggered
   */
  public focused() {
    this.hasHadFocus = true;
  }

  /**
   * Called when input (blur) is triggered
   */
  public blurred() {
    if (this.hasHadFocus && !this.hasNotifiedTouched) {
      this.hasNotifiedTouched = true;
      this.propogateTouched();
    }
  }

  /**
   * Called when a new value is set via code
   * @param obj
   */
  writeValue(value: any): void {
    this.value = value;
  }

  /**
   * Register Angular's call back to execute when our value changes
   * @param fn
   */
  registerOnChange(fn: any): void {
    this.propagateChange = fn;
  }

  /**
   * Register Angular's call back to execute when our value is first touched
   * @param fn
   */
  registerOnTouched(fn: any): void {
    this.propogateTouched = fn;
  }
}

TypeScript - A polyfill to extend the Object class to add a values property to complement the keys property

I expect you've used Object.keys at some point. Here is how to extend the Object class to add a values property. This kind of thing is useful when you have a lookup of keys where all of the values are the same type, such as the following object you'd expect to see in a Redux app.

{
  "gb": { code: "gb", name: "Great Britain" },
  "us": { code: "us", name: "United States" }
}

The code


interface ObjectConstructor {
  values<T>(source: any): T[];
}

/**
 * Extends the Object class to convert a name:value object to an array of value
 * @param source
 * @returns {T[]}
 */
Object.values = function<T>(source: any): T[] {
  const result = Object.keys(source)
    .map(x => source[x]);
  return result;
}

TypeScript - Get a Lambda expression as a string

One of the things I really like about C# is the ability to convert a lambda into a string. It's useful for doing all kinds of things, especially when you are calling a 3rd party library's method that expects a string identifying a member of an object.

I saw this was lacking in TypeScript, which was a pain because I wanted to make various parts of my Angular application more compile-time resilient to changes in the server's API model.

Using the following code it is possible to take a call like this
someObject.doSomething<Person>(x => x.firstName)
From there we can get the name of the property referenced in the lamba expression. In fact it will return the entire path after the "x."
abstract class Expression {
  private static readonly pathExtractor = new RegExp('return (.*);');

  public static path<T>(name: (t: T) => any) {
    const match = Expression.pathExtractor.exec(name + '');
    if (match == null) {
      throw new Error('The function does not contain a statement matching \'return variableName;\'');
    }
    return match[1].split('.').splice(1).join('.');
  }
}

Example

The following example will show the string 'country.code'
interface Address {
    line1: string;
    country: {
        code: string;
        name: string;
    }
}

const result = Expression.path<address>(x => x.country.code);
alert('Result is ' + result);

2017-08-10

Angular - How to create composite controls that work with formGroup/formGroupName and ReactiveForms

This blog post will show you how to create composite controls in AngularX that allow you to reuse them across your application using the formGroupName directive to data-bind them.

We'll start off with a very basic component that uses a reactive form to edit a person and their address.

Editing a person's name and address


import {Component, OnInit} from '@angular/core';
import {FormBuilder, FormGroup} from '@angular/forms';

@Component({
  selector: 'app-root',
  template: './app.component.html',
})
export class AppComponent implements OnInit {
  public form: FormGroup;

  constructor(private formBuilder: FormBuilder) {}

  ngOnInit(): void {
    this.form = this.formBuilder.group({
      name: 'Person\'s name',
      address_line1: 'Address line 1',
      address_line2: 'Address line 2',
    });
  }
}
<form novalidate [formGroup]="form">
  <div>
    Name <input formControlName="name"/>
  </div>
  <div>
    Address line 1 <input formControlName="address_line1"/>
  </div>
  <div>
    Address line 2 <input formControlName="address_line2"/>
  </div>
</form>

Making the address editor a reusable component

At some point it becomes obvious that Address is a pattern that will pop up quite often throughout our application, so we create a directive that will render the inputs wherever we need them.

First, change the formBuilder code in the parent component so that address is a nested group.

  ngOnInit(): void {
    this.form = this.formBuilder.group({
      name: 'Person\'s name',
      address: this.formBuilder.group({
        line1: 'Address line 1',
        line2: 'Address line 2',
      })
    });
  }

Then we need to change the html template in the parent component so that it uses a new composite control instead of embedding the html input controls directly. To pass the context to our composite child control we need to use the formGroupName attribute.

<form novalidate [formGroup]="form">
  <div>
    Name <input formControlName="name"/>
  </div>
  <address-editor formGroupName="address"></address-editor>
</form>

The html of the edit-address component is quite simple. As with the main component we will need a [formGroup] attribute to give our inner inputs a context to data bind to.

<div [formGroup]="addressFormGroup">
  <div>
    Address line 1 <input formControlName="line1"/>
  </div>
  <div>
    Address line 2 <input formControlName="line2"/>
  </div>
</div>

Finally we need our edit-address component to provide the addressFormGroup property the view requires for its [formGroup] directive. To do this we need a ControlContainer reference, which is passed in via Angular's dependency injection feature. After that we can use it's control property to get the FormGroup specified by the parent view. This must be done in the ngOnInit method, as ControlContainer.control is null at the point the embedded component's constructor is executed.

import {Component, OnInit} from '@angular/core';
import {ControlContainer, FormGroup} from '@angular/forms';

@Component({
  // Ensure we either have a [formGroup] or [formGroupName] with our address-editor tag
  selector: '[formGroup] address-editor,[formGroupName] address-editor',
  templateUrl: './address-editor.component.html'
})
export class AddressEditorComponent implements OnInit {
  public addressFormGroup: FormGroup;

  // Let Angular inject the control container
  constructor(private controlContainer: ControlContainer) { }

  ngOnInit() {
    // Set our addressFormGroup property to the parent control
    // (i.e. FormGroup) that was passed to us, so that our
    // view can data bind to it
    this.addressFormGroup = this.controlContainer.control;
  }
}

Summary

That's all there is to it! Writing a component that edits a composite data structure is even easier than writing a custom control for editing a single piece of data (FormControl) - which I will probably describe in another blog entry.