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

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
(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.

2017-07-08

Redux sub-reducer pattern for complex / nested data structures

I love the idea of the Redux pattern, the way all reducers are pure and predictable. I love the way they are effectively listeners that act on event notifications received from a central dispatcher, and I really like the way the whole approach simplifies the application and makes code in my Angular app's components only concerned with view related concerns rather than business logic. However, what I am not a big fan of is the normalised data approach. I've seen it recommended so many times for use with the Redux approach. You essentially have any object (read "row from table on server") in memory once and then everywhere else you hold a reference to the locally stored record/object by its unique ID. So, a view state you receive that looks like this

[
  { "id": "Emp1024", "name": "Peter Morris", "address": { "id": "123", "street": "xxx" } },
  { "id": "Emp4096", "name": "Bob Smith", "address": { "id": "254", "street": "yyy" } }
]

Might be flattened out to something like this

{
  "people": {
    "Emp1024": { "name": "Peter Morris", "address": "123" },
    "Emp4096": { "name": "Bob Smith", "address": "254" },
    "_ids": [ "Emp1024", "Emp4096" ]
  },
  "addresses": [
    "123": { "street": "xxx" },
    "254": { "street": "yyy" }
  ]
}

What I do like about this is approach

  1. When your reducer has to locate an object to update it, it can find it immediately without having to iterate over the whole array.
  2. Only objects (rows) that have their state affected by the dispatched notification will be recreated, the rest will be copied as-is into the new array of objects 

What I don't like about this is

  1. API servers don't usually return data in a normalised format, so the client has to normalise data from the server (especially if you don't own the server code and cannot change it).
  2. Because the keys of an object can be stored in an indeterminate order we have to maintain an additional property containing an array of the Ids so we know in which order to display them.
  3. A local copy of the remote data is cached locally by the client and isn't unloaded.
My preferred approach is to have state per task, like so

  {
    "task1": { .............. },
    "task2": { .............. },
    etc
  }

The state that each task (read "route") works with can be exactly what the server sent to the client. We can clear out unwanted state in the core reducer by only keeping cross-task data whenever the client's route changes (such as user-name, session token etc).


function coreReducer(state: any, action: Action) {
  switch (action.type) {
    case 'ChangeRoute': 
      return { loginInfo: state.loginInfo };
         
    default:
      return state;
  }
}

Of course, normalised data can be cleared down in this way too, when switching between tasks. However, imagine a task such as "Dashboard" onto which users can drop any number of widgets that present server data of all kinds. As these widgets update their data they are unable to relinquish any data they previously loaded, because without reference counting on everything they refer to there is no way to know which rows of data are not being used by any of the other widgets currently on screen. But if our data is nested then each widget contains all of the data it needs at any moment. Some of the same data (addresses, employees, etc) may exist in memory on the client more than once (one per widget) but that data is unloaded when finished with. The use of additional memory means that our memory usage doesn't creep up throughout the day.

To reduce nested (complex) data is quite easy. Using an approach I learned on a Martin Odersky course it is possible to change an object at the left of a complex data tree without having to replace the entire tree.



export const subReduce = (state: any, action: any, reducers: any) => {
  // If we have an original state then copy it, otherwise keep a null state
  let newState = state ? {...state} : null;
  for (const key of Object.keys(reducers)) {
    // Grab the previous member state. If passed state is null the member state is null
    const previousMemberState = state !== null ? state[key] : null;
    const reducer = reducers[key];
    const newMemberState = reducer(previousMemberState, action);

    // Scenarios are
    // 1: No initial state object and new member state is null = keep null state
    // 2: No initial state object and has new member state = new state + set member
    // 3: Has initial state object and member state set = keep state + set member
    // 4: Has initial state object and member state is null = keep state + unset member
    // If we need to set a member to a non null value then we need an instance
    if (newState === null && newMemberState) {
      newState = {};
    }
    if (newState) {
      newState[key] = newMemberState;
    }
  }
  return newState;
}

There is still a reducer per object type, but these reducers are now nested too. They used the subReduce() function to declared their complex child properties.


export const addressReducer = (state: Address = null, action: any) => {
  switch (action.type) {
    case 'address.update':
      return Object.assign({}, state, action.payload);
  }
  return state;
}

export const addressArrayReducer = (state: Address[] = null, action: any) => {
  if (!state) {
    return state;
  }

  return state.map(x => {
    if (x.id === action.payload.id) {
      return addressReducer(x, action);
    } else {
      return x;
    }
  });
}

export const personReducer = (state: Person = null, action: any) => {
  state = subReduce(state, action, {
    addresses: addressArrayReducer
  });
  switch (action.type) {
    case 'person.setName':
      return {
        ...state,
        name: action.payload
      };
  }
  return state;
}

export const rootReducer = {
  person: personReducer
}

Of course, you can use this approach and still use normalised data to benefit from the redundant data-unloading whilst keeping your normalised data.


{
  task1: null,
  task2: null,
  dashboard: {
    widget1: {
      "people": {
        "Emp1024": { "name": "Peter Morris", "address": "123" },
        "Emp4096": { "name": "Bob Smith", "address": "254" },
        "_ids": [ "Emp1024", "Emp4096" ]
      },
      "addresses": [
        "123": { "street": "xxx" },
        "254": { "street": "yyy" }
      ]
    },
    widget2: { /* whatever */ },
    widget3: {
      "people": {
        "Emp1024": { "name": "Peter Morris"},
        "Emp4096": { "name": "Bob Smith"},
        "Emp8192": { "name": "Aled Jones"},
        "_ids": [ "Emp4096", "Emp8192", "Emp1024" ]
      }
    }
  },
}

2017-06-14

Loading an assembly from a specific path, including all sub dependencies

    public static class AssemblyLoader
    {
        private static readonly ConcurrentDictionary<string, bool> AssemblyDirectories = new ConcurrentDictionary<string, bool>();

        static AssemblyLoader()
        {
            AssemblyDirectories[GetExecutingAssemblyDirectory()] = true;
            AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;

        }

        public static Assembly LoadWithDependencies(string assemblyPath)
        {
            AssemblyDirectories[Path.GetDirectoryName(assemblyPath)] = true;
            return Assembly.LoadFile(assemblyPath);
        }

        private static Assembly ResolveAssembly(object sender, ResolveEventArgs args)
        {
            string dependentAssemblyName = args.Name.Split(’,’)[0] + ".dll";
            List<string> directoriesToScan = AssemblyDirectories.Keys.ToList();

            foreach (string directoryToScan in directoriesToScan)
            {
                string dependentAssemblyPath = Path.Combine(directoryToScan, dependentAssemblyName);
                if (File.Exists(dependentAssemblyPath))
                    return LoadWithDependencies(dependentAssemblyPath);
            }
            return null;
        }

        private static string GetExecutingAssemblyDirectory()
        {
            string codeBase = Assembly.GetExecutingAssembly().CodeBase;
            var uri = new UriBuilder(codeBase);
            string path = Uri.UnescapeDataString(uri.Path);
            return Path.GetDirectoryName(path);
        }
    }

2017-06-08

Running dotnet core xUnit tests on Visual Studio Team Services (VSTS)


1: Run dotnet restore to restore package dependencies.

2: Run dotnet build to build the binaries.

3: Run dotnet test to run the tests. Note the additional parameters --no-build to prevent a rebuild and --logger "trx;LogFileName=tests-log.trx" to ensure the test results are written to disk,

5: Use  a Publish Test Results tasks to output the results of the tests. Make sure you set the following properties
  • Test Result Format = VSTest
  • Test Results Files = **/tests-log.trx
And under the Advanced section make sure you set the Run This Task option so that it will run even if the previous task failed.