Learning Angular 2: Upgrading to Angular 2 RC5

Angular 2 , Angular 2 Learning , IntelliJ IDE No Comments »

Version 0.0.3 of my GuildRunner sandbox Angular 2 application is now available.  All of the differences between this version and the previous version (minus the updates to the version number and the README file) are changes made to upgrade the application to use Angular 2 RC5 (release candidate 5).

While there were some changes to the router/routing syntax, the biggest change that comes with RC5 is the introduction of Angular modules and the @ngModule decorator.  There is a long documentation page about Angular modules in the official developer guide, but essentially Angular modules allow you to bundle sets of shared injectable dependencies into a single file that provides those dependencies "downstream".

Read more...

Augury: An Elegant Tool For Inspecting Angular 2 Applications

Angular 2 No Comments »

In episode 105 of the Adventures in Angular podcast, the panel spoke with one of the developers behind an open-source development tool called Augury. Augury is a Chrome extension that adds an "Augury" tab to the Chrome Development Tools panel, and that tab displays real-time information regarding Angular 2 activity on the current web page.

Read more...

Learning Angular 2: Adding a Master Guild List Component To My Sandbox Application

Angular 2 , Angular 2 Learning No Comments »

I recently released version 0.0.2 of my GuildRunner sandbox Angular 2 application.  Changes made during this release include:

  • The addition of a Bootstrap-powered navigation bar (main-navigation.component.ts) which necessitated adding CDN calls for jQuery and Bootstrap JS (index.html).
  • The addition of Angular 2 routing (main.ts, app.routing.ts).
  • The creation of guild data for use by the in-memory web API (db/guilds.ts).
  • The creation of Guild, Address, and Member domain classes to be populated with the guild data (the address.ts, guild.ts, and member.ts files in the "domain" folder) via the GuildService (guild.service.ts).
  • The creation of a master view that displays data from a list of Guild objects within a table (guilds-master.component.ts).
  • The creation of a "sandbox" area of the application where I can keep experimental and diagnostic features (the "sandbox" folder). 

Some lessons learned during the coding of this release:

The in-memory web API has limitations

The in-memory web API is currently limited to mimicking a shallow data graph. It allows you to mock the following types of REST calls:

  • app/guilds (to retrieve all guilds)
  • app/guilds/1 (to retrieve the guild with an id of 1)
  • app/guilds/?name=Blacksmiths (to retrieve the guild or guilds based on the query string)

...but you cannot simulate deeper REST calls:

  • app/guilds/1/members/1 (retrieving the member with id of 1 from guild 1)

For this application at this particular point, it's not a big deal, but I will probably be looking at alternatives methods for faking HTTP calls at some point down the line.

Instantiating domain model classes

In the Tour of Heroes tutorial, the instructions have you create a Hero class with properties for the id and name of the hero. Later, that class is used to declare a component variable with a data type of an array of Heroes:


heroes: Hero[];

...which is then populated with the hero data, an array of object literals:


[
  {id: 11, name: 'Mr. Nice'},
  {id: 12, name: 'Narco'},
  ...
]

...like so:


this.heroService.getHeroes().then(heroes => this.heroes = heroes);

From a coding standpoint, declaring the "heroes" variable as an array of Hero objects ensures that another developer cannot use code to populate that variable with anything but Hero objects, but that declaration is meaningless at runtime. Doing the same thing with my guild data:


//Populates the "guilds" variable with the raw retrieved data (array of object literals)
export class GuildsMasterComponent implements OnInit {

  guilds: Guild[];
  constructor( private guildService: GuildService ) { }

  ngOnInit() {
    this.guildService.getGuilds().then( guilds => this.guilds = guilds )
  }
}

...results in the "guilds" variable being populated with the raw array of guild object literals, each with an address object literal and an array of member object literals. But that's not what I wanted: I wanted an array of Guild objects with included Address and Member objects.

So I wrote the code to instantiate the desired objects, populating the property values via the constructor method:


//guilds-master.component.ts
...
import { Guild } from '../domain/guild';
...
export class GuildsMasterComponent implements OnInit {

  guilds: Guild[] = [];
  
  constructor( private guildService: GuildService ) { }

  ngOnInit() {
    this.guildService.getGuilds().then( guilds => {
      guilds.forEach( guild => {
        this.guilds.push( new Guild( guild ) )
      })
    } );
  }
}

//guild.ts
import { Address } from './address';
import { Member } from './member';

export class Guild {
  id: number;
  name: string;
  expenses: number;
  revenue: number;
  profit: number;

  address: Address;
  members: Member[] = [];

  constructor( guildData:any ) {
    this.id = guildData.id;
    this.name = guildData.name;
    this.expenses = guildData.expenses;
    this.revenue = guildData.revenue;

    this.profit = this.calculateProfit();

    this.address = new Address( guildData.address );

    guildData.members.forEach( member => {
      this.members.push( new Member( member ) );
    }, this );

  }

  calculateProfit() {
    return this.revenue - this.expenses;
  }

}

Providing my master view with an array of Guild objects allowed me to display the profit of each guild in addition to the raw guild data provided by the in-memory web API.

The currency pipe

This release marked my first time using one of the built-in Angular 2 pipes, though it was pretty similar to my experiencing using the built-in filters in Angular 1.

I was a tad surprised that the default CurrencyPipe settings would result in the number being prefixed with "USD" rather than a dollar sign. But a quick glance through the CurrencyPipe documentation gave me the settings I wanted and instructions on how to further control the output with the DecimalPipe:


<td align="right”>{{guild.revenue | currency:'USD':true:'.2-2' }}</td>

In cases where you wanted your application to support internationalization, I imagine you could use a component variable to dynamically affect the currency code:


<td align="right”>{{guild.revenue | currency:currencyCode:true:'.2-2' }}</td>

 

IntelliJ, Angular CLI, and Indexing

Angular CLI , IntelliJ IDE No Comments »

As I started working on my Angular CLI-managed Angular 2 project, I discovered that making code changes while Angular CLI was either serving my application or waiting to re-execute unit tests would cause my IntelliJ IDE to start re-indexing my project files.  Each indexing run took several minutes and during that time IntelliJ was slow to respond to my attempts to edit and interact with the code files.

I solved this performance issue by selecting the "Project Structure" / "Project Settings" menu item, selecting "Modules", and marking the following folders as "Excluded" on the "Source" tab:

  • dist
  • tmp
Those two folders are created and updated by Angular CLI automatically while testing and serving the application: there's no benefit in having the IDE index them.

Learning Angular 2: Creating My First Sandbox Web Application

Angular 2 , Angular 2 Learning , Angular CLI , IntelliJ IDE No Comments »

While there is still a lot out there for me to read regarding Angular 2, I tend to learn by coding and solving problems.  Even though there are a few aspects of Angular 2 that are in flux at this time (like forms), I feel that I can start writing an application without much fear that I'd have to go back and redo things because the API has changed.

So I've created my first "sandbox" Angular 2 application where I can practice writing Angular code and figure out ways to accomplish specific application tasks with Angular 2.  I'm going to keep a copy of the code up on GitHub and release milestones in my development so that I have a historical picture of the development and so I can potentially backtrack and create different solutions to a given problem.  Plus, it will allow anyone to pull down a tagged version on their own machine to look at the code.

My first sandbox is an application called "GuildRunner".  My plan is that it will be an application for managing a fictional collection of trade guilds, and so I can use it to exploring dealing with common application issues like authentication and authorization, data relationships, and searching.  But I wanted to start by simply creating the foundation for the application structure and getting it up and running.

Read more...