Posts

Assigning a piped async result to a variable in an Angular view

If you have an Observable<x> in your component you might find yourself doing something like this {{ ( source$ | async)?.property1 }} {{ ( source$ | async)?.property2 }} This will subscribe to the source$ observable more than once. A commonly used technique to avoid this is to assign the result of the async into a view variable, like so: <ng-container ngif="source$ | async as source">   {{ source?.property1 }}   {{ source?.property2 }} </ng-container> But if you have other UI elements within that ng-container that you want to be displayed whether or not source$ has emitted a value then you might not like the fact that a portion of your UI is excluded until the observable emits a value or when the observable emits a falsey value. If that is the cast, you can try this little trick. <ng-container ngif="(source$ | async) || {} as source">   {{ source.property1 }}   {{ source.property2 }} </ng-container> We utilise *ngIf ...

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

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) .addFormContro...

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.

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

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