Angular Array Filter Framework

We are currently working on an Angular application that has many different types of domain specific objects all of which have a common set of base attributes, “isDeleted” and “title” to name a few.

[code language=”javascript”]
export interface EntityDomainModelBase {
code: string;
title?: string;
isDeleted?: boolean;
}
[/code]

There are a few areas within the application that will need to filter arrays of the domain specific objects by both some domain specific attributes and also by the base attributes.  A base Angular “pipe” class was created to encapsulate the plumbing of the filter and the filter logic for the common base attributes, along with the delegation to the domain specific subclass.

[code language=”javascript”]
import { PipeTransform } from ‘@angular/core’;

import { EntityDomainModelBase } from ‘./api/DomainModelBase’;

export class DomainModelArrayFilterPipeContext {
viewDeleted: boolean;
searchTerm: string;
}

export class DomainModelArrayFilterPipe<typeOfEntity extends EntityDomainModelBase>
implements PipeTransform
{
transform(entities: typeOfEntity[], ctx: DomainModelArrayFilterPipeContext) {

if (!ctx)
return entities;
if (!entities || !entities.length)
return entities;

return entities.filter((item: typeOfEntity) => {
return (ctx.viewDeleted == undefined || item.isDeleted == ctx.viewDeleted)
&& (ctx.searchTerm == undefined || ctx.searchTerm == ”
|| item.title.toLowerCase().indexOf(ctx.searchTerm.toLowerCase()) >= 0
|| this.checkTerm(item, ctx.searchTerm)
);
});
}

/*
implement in domain specific filter class to filter on domain specific attributes
*/
checkTerm(item: typeOfEntity, searchTerm: string): boolean { return true; }
}
[/code]

A domain specific subclass was then created and used like any other “@pipe” attributed class. This domain specific pipe implementation also filters through an array of persons for a specific name.

[code language=”javascript”]
@Pipe({ name: ‘domainSpecificObjectFilter’ })
export class DomainSpecificFilterPipe extends DomainModelArrayFilterPipe<SomeDomainModel> {
checkTerm(item: SomeDomainModel, searchTerm: string): boolean {
return item.persons.filter(p => p.name.toLowerCase().indexOf(searchTerm.toLowerCase()) >= 0).length > 0;
}
}
[/code]

The filter classes above are then used to filter a list of domain specific objects and draw the appropriate HTML.

[code language=”html”]
<ng-container *ngFor="let event of (events | eventsFilter:filterContext)">
[/code]

With this design any number of domain specific filtering scenarios can be addressed without having to duplicate the common argument checking and array filtering logic.

Angular Dirty Tracking of Object Graphs

I am currently working on a CRUD app in Angular and needed to implement dirty tracking of an object graph.  All the examples I have found work well on the “input” properties to a component, or for simple objects using the “KeyValueDiffer”.

I started implementing the logic based upon this post Angular Change Detection but As soon as I tried to edit a collection or property of the root object I would need to do traverse the nested objects and arrays.

I then decided to keep it simple and just compare JSON strings of the original object and any changes that occur to it during the edit cycle.  This approach would allow the user to change a property back to it’s initial state using normal editing procedures.  Editing an “input” and then just changing the text back would reset the dirty, adding a collection item then removing it after add would reset the dirty, etc.

[code language=”javascript”]
updateDirty(): boolean {

var currentJson: string = JSON.stringify(this.entity);
this.isDirty = currentJson != this.originalJson;

return this.isDirty;
}

editStart(entity: typeOfEntity) {
this.entity = entity;
this.isDirty = false;

this.originalJson = JSON.stringify(entity);
}
[/code]

Angular Constants Injected Server Side from ASP.NET CSHTML

Most answers on the internet work well for JIT compilation, refer to the stack overflow article here;  Stack Overflow Question

We are using JIT compilation for development and AOT for deployment. I couldn’t find a good way to make the standard approach work with AOT. For reference I followed the AOT cookbook here… Angular AOT cookbook.

The approach below will not work for server side rendering but should suffice for both JIT and AOT client side rendering.

1) In the razor view, _layout.cshtml for example, just put a script block and set a JSON object on the window interface. I placed this block within the “head” tag but doesn’t really matter. The values for the JSON keys can be determined by any razor syntax.

[code language=”javascript”]
window.appContext = {
userName: ‘@("test".ToUpper())’,
isAdmin: @(1 == 1 ? "true" : "false")
};
[/code]

2) Create an app context service and wire up in appropriate module and inject into components for usage, if you need help with this just comment and I’ll supply more info.

[code language=”javascript”]
import { Injectable } from ‘@angular/core’;

/*
must match definition in SCRIPT tag that is seeded from razor
*/
interface IAppContext {
userName: string;

isAdmin: boolean;
}

/*

*/
@Injectable()
export class AppContextService implements IAppContext {

userName: string;

isAdmin: boolean;

constructor() {
var appContextBootstrap: IAppContext = (<IAppContext>(<any>window).appContext);

this.userName = appContextBootstrap.userName;
this.isAdmin = appContextBootstrap.isAdmin;
}

}
[/code]

3) reference and use the app context service throughout the application.

[code language=”javascript”]
import { Component } from ‘@angular/core’;

import { AppContextService } from ‘./appContext.service’

@Component({
moduleId: module.id,
selector: ‘story-app’,
templateUrl: ‘app.component.html’
})
export class AppComponent {
AppConfig: any;
constructor(private appContext: AppContextService) { }

ngOnInit() {

alert(‘hi – ‘ + this.appContext.userName);
}
}
[/code]

Planning and Events Product

In 2017, EmpireCLS wanted to simplify the management of events. An event was a large number of people being driven to and from venues. A venue would be for as little as a single day or up to several days or weeks long. This was an extremely manual process and required many staff hours to manage and validate.

We developed the entire MVP using a “no DB” approach. In order to cut down on the friction of any type of database we used in memory repositories to track all data. A generic set of classes were used to manage the memory repository and offered simple migration to full DB support. We used domain models from the repositories as the application view of data, the repositories would then map the domain models into whatever storage we wanted; mongo, SQL, etc.

We used Typewriter to generate our client typescript code based upon the web API interface, API models, and domain models. By authoring a few templates in Typewriter we would have all of the client-side Angular HTTP services, DTO’s, and view models generated for us. This streamlined the development process immensely.

Technologies… C#, asp.net MVC, asp.net Web API, Angular, Typewriter

On Demand Product

In 2016, EmpireCLS wanted to build a new product to tackle on-demand for the corporate customer. This product was to have a no-touch integration with their 400+ affiliate network and provide real-time availability of inventory through the EmpireCLS customer app.

We developed the entire MVP using a “no DB” approach. In order to cut down on the friction of any type of database we used in memory repositories to track all data. A generic set of classes were used to manage the memory repository and offered simple migration to full DB support. We used domain models from the repositories as the application view of data, the repositories would then map the domain models into whatever storage we wanted; mongo, SQL, etc.

We used Typewriter to generate our client typescript code based upon the web API interface, API models, and domain models. By authoring a few templates in Typewriter we would have all of the client-side Angular HTTP services, DTO’s, and view models generated for us. This streamlined the development process immensely.

The project was put on hold indefinitely after a simplified POC was delivered to the executive team.

Technologies… C#, asp.net MVC, asp.net Web API, AngularJS, Typewriter

Suggestive Dispatch Software

In 2014, EmpireCLS wanted to optimize their dispatch department by automating the chauffeur to reservation assignments that they have been manually doing for decades.

Building on the rules of the newly created dispatch application this application would attempt to automate as much of the work as possible. Some of the rules that would need to be taken into consideration are as follows; driver requests by customer, driver location to customer, VIP customer handling, where driver started their day, shift time, etc.

A real-time GPS tracking system was also required for this system so as to have constant visibility to driver location and time / duration to a customer location or when the customer would be dropped off.

We ended up treating output of the system as suggestions that the dispatcher could just accept as opposed to 100% automation. There were edge cases that could not be covered for 100% automation so suggesting vs. automating was the better solution.

A dispatcher using this tool was able to assign all of the work for the first shift drivers in seconds, where previously it took over an hour.

Technologies… C#, asp.net MVC, Mongo, SQL Server

Kindred Gamer

In 2014 we set out to build a website to help with offline matchmaking for video game players.

This was a labor of love. A couple of us were really into multi-player gaming on the Xbox and wanted to have a social site where players of varying skills could locate other gamers of like skill and coordinate online games with each other. We were basically sick of getting totally owned by the kids that played several hours a day and wanted to play with people closer to our skill level, age, and status.

There were several game specific sites and apps that players were using but we wanted to build a framework to support all games on all platforms. Destiny was the big game at the time and one that we spent a lot of our time playing so we used it as a model. We were able to quickly fit Call of Duty, Halo, and all of the other AAA titles easily into the mix.

We did actually finish the site and it is still publicly available in a limited fashion.

The idea was sound and the market was tested before we started to build it. We did initial testing on Facebook buy putting out a couple of small ads to see if players were interested. We ended up getting around 300 or so likes in 2 days so in our minds this seemed like a great idea. We still get a few likes here and there but do not advertise or support the site.

We ended up putting the project on hold once Xbox Live came out with their own version. We couldn’t compete with Xbox because they had the profile and game related data to help drive player “likeness”. We had to rely on players manually entering their data, which wasn’t the best approach but was the only thing we could do at the time.

We built the site using asp.net MVC / Web API, AngularJS, JQuery, Ajax, etc. The notion of server side design-time data was used to help speed up the client side development, this pushed all database development to the end and allowed us to quickly iterate on the UI.

The site is still available with limited functionality for all to see here.

Tranquility Product

In 2012, EmpireCLS needed to build out their new platform that would replace their existing Linux platform lovingly known as Iliad. We termed the new platform “Tranquility” to try and install a sense of calmness for those migrating from the legacy platform.

The existing linux platform had around 1 million lines of code, over 200 applications, and 20 years of data in an ISAM database. Our goal was to build this new web platform on Windows and slowly migrate the individual programs.

From the onset we counted on running both systems side by side and slowly migrating users to the new system. We chose the side by side approach to cut down on risk to the company, simplify training, and allow real-time validation between systems.

The initial modules that were moved were read-only; customer profiles, reservations, chauffeur HR. New modules were added to support credit card rebills, chauffeur check-ins, system monitoring, and several third party integration portals.

Technologies… C#, asp.net MVC, SQL Server, asp.net web API, Angular, Typescript