Angular 4: Changes in the router

Angular 4 comes with some useful changes in the router. Let’s take a look at the changes in receiving parameters by a route and in the CanDeactivate guard (see here).

A route can receive the parameters either using a snapshot property of the ActivatedRoute or by subscribing to its property param. Now there is a property paramMap that allows you to either get a particular parameter by using the method get() or get all parameters by invoking getAll().

Here’s how to receive a parameter id that’s not changing in the parent:

export class ProductDetailComponentParam {
  productID: string;

  constructor(route: ActivatedRoute) {
    this.productID = route.snapshot.paramMap.get('id');
  }
}

If the parameter id is changing in the parent (as described here), you can subscribe to the stream of id’s as follows:

export class ProductDetailComponentParam {
  productID: string;

  constructor(route: ActivatedRoute) {

    route.paramMap.subscribe(
     params => this.productID = params.get('id')
     );
  }
}

The CanDeactivate guard now allows you to be more specific and conditionally prohibit navigating from a route depending on where the user is planning to navigate. The interface CanDeactivate now has an optional parameter nextState, which you can check to decide if you want to prohibit the navigation or not. The next code snippet shows the guard that would display a warning popup only if the user is trying to navigate to the home route represented by the path ‘/’. The navigation to any other routes remains unguarded.

@Injectable()
export class UnsavedChangesGuard implements CanDeactivate<ProductDetailComponent>{

    constructor(private _router:Router){}

    canDeactivate(component: ProductDetailComponent, 
                  currentRoute: ActivatedRouteSnapshot,
                  currentState: RouterStateSnapshot, 
                  nextState?: RouterStateSnapshot){

        let canLeave: boolean = true;

        // If the user wants to go to home component
        if (nextState.url === '/') {
          canLeave = window.confirm("You have unsaved changes. Still want to go home?");
        }
        return canLeave;

    }
}

Angular 4 was just released and there might be some other goodies in the router, but I just wanted to share with you these convenient additions.

Upgrading to the latest Angular CLI

As of the Angular CLI beta 30, the command to install Angular CLI looks as follows:

npm install -g @angular/cli

To get rid of the old version of Angular CLI and install the new one, run the following commands:

npm uninstall -g angular-cli
npm cache clean
npm install -g @angular/cli

To update the existing CLI projects, modify the CLI dev dependency in package.json to this:

"@angular/cli": "1.0.0-beta.32"

Then update the CLI version on top of the angular-cli.json, remove your node_modules dir and run npm install.

My upcoming speaking engagements

In the upcoming six months of 2017 I’ll be speaking at the following conferences:

1. BuzzJS, New York City, January 27, 1 talk

2. DevNexus, Atlanta, February 22-24, 2 talks

3. DevoxxUS, San Jose, March 21-23, 2 talks

4. Angular Summit, Chicago, May 10-11, 8 talks (my personal record!)

5. JEEConf, Kiev, Ukraine, May 26-27, TBD

6. JCrete, Crete, Greece, July 17-21, TBD

Hope to see you at one of these events!

Angular 2: What’s with the name?

The Angular 2 framework now supports semantic versioning, and it was announced that major upgrades (with breaking changes) will be released twice a year. In particular, in March of 2017 the version 4.0.0 will be released, in September – 5.0.0 and so on.

This is all good but the problem is that not only the versioning will be different, but Angular team is considering changing the name from Angular 2 to Angular. This will create lots of confusion in the Angular community.

First, a bit of history. The older version of this super popular Web framework is called AngularJS (currently at 1.6.0). Two years ago a complete redesign of this framework was announced, and the new framework got the name Angular 2. I guess, someone at Google suggested to keep the word Angular in the name to leverage the fact that more than 1.3 million of software developers were already using AngularJS, and most of these people would want to upgrade to the newer version of the same framework.

The problem is that Angular 2 is completely different framework, and suggesting the roadmap for upgrading existing AngularJS apps to Angular 2 is no different than suggesting a roadmap for upgrading an app from Ember or React to Angular 2. But the marketing plan worked out nicely, and more than 700K developers are using Angular 2 by now. No wonder – Angular 2 is a great framework.

People started creating Angular 2 communities to post articles, and ask for help. For example, the Reddit’s Angular 2 community is pretty active and has 6800 members: https://www.reddit.com/r/Angular2/. Questions and answers on StackOverflow are marked with the tag #angular2: http://stackoverflow.com/questions/tagged/angular2. LinkedIn has a group of 7900 Angular 2 developers: https://www.linkedin.com/groups/8434339.

Bloggers (myself included) are posting articles and tutorials that have Angular 2 in their names. PluralSight, Lynda.com, egghead.io and many independent developers produce video contend with Angular 2 in their titles.

Book authors (myself included) wrote about a dozen books with Angular 2 in their titles, and these books will remain relevant and useful for several years, unless Google will decide to completely re-write this framework again.

If the framework will be renamed to Angular, anyone searching for Angular 2 content will be inevitable getting materials for both AngularJS and Angular 2. Just try finding posts on StackOverflow tagged as Angular: http://stackoverflow.com/questions/tagged/angular. The “angular” in the URL will be automatically converted to “angularjs” and you’ll be seeing 200K+ irrelevant posts about AngularJS. IMO, it’s a disservice to the community. BTW, there is Angular Reddit group as well: https://www.reddit.com/r/angular, and these developers may want to keep their forum clean from Angular 2 posts.

I suggest to keep Angular 2 as the name of the framework. The digit 2 here won’t represent the version, but rather the next generation of this framework. So in March we’ll get Angular 2 v. 4.0.0, in September – Angular 2 v.5.0.0 and so on. Content producers can still include “Angular 2” in the titles and use the tag #angular2 in social networks.

What do you think?

P.S. The community may decide to keep using the tag #angular2 regardless of the official name of this framework.

A Web developer’s reading list

Manning is planning to release a free book sampler that would include chapters from different books covering modern Web development process. They asked me to select books/chapters and write a short intro, which I did and decided to share this with you.

The modern world of Web development requires software engineers who are well versed in multiple disciplines. Of course, familiarity with the JavaScript syntax is a must. As Atwood’s law states, “Any application that can be written in JavaScript, will eventually be written in JavaScript”. Well, maybe not in the pure JavaScript, but in its more productive superset called TypeScript.

Web developers use frameworks and/or libraries to avoid re-inventing the wheel while working on applications. While many people are still happy with jQuery, more progressive developers are debating: Angular or React? This comparison is wrong because React is a library while Angular is a framework with batteries included. But Angular and React are the most popular tools in the Web development ecosystem today.

There is a trend to develop applications using principles of reactive programming. The data consumer subscribes to the data stream that’s pushed to the consumer only when the data is available. This is an alternative to the polling model that requires the client to make periodic requests for data, which may or may not not be available. The RxJS library implements the push model via observable streams of data. This library offers you a variety of chainable operators (functions) that handle and transform the data en route.

Making your application available on mobile devices is important. Will your Web application look good on a small screen or you’d better create separate native applications for each mobile platform? There is is a third approach to create so called hybrid applications that run a Web container inside your mobile device translating HTML elements into their native counterparts. Actually there is a forth approach that suggests reusing the most of the code base of your Web app while compiling the UI portion into native mobile components before the app is deployed. NativeScript is one of the frameworks that does it.

Most Web applications would need to provide login and user authentication/authorization. The chances are that you’ve been offered by some apps to login using their FaceBook or Twitter account. Usually such authorization is implemented using OAuth protocol. You can set up authorization using privately installed OAuth server that fits nicely with RESTful Web services.

This book sampler will give you a taste of multiple facets of the modern development of Web and mobile applications. Some of the books are already released while others are still in the works, but you can reading drafts via Manning’s MEAP program.

For this sampler I’ve suggested selected chapters from the following books:

1. RxJS in Action MEAP

2. Angular 2 Development with TypeScript

3. React in Action MEAP

4. NativeScript in Action MEAP

5. OAuth 2 in Action MEAP

This is not a complete list and there are other fine books being released by many book publishers. Here’s my message to you

“Read.Study.Write.Repeat.”

Happy reading!

Angular 2: Implementing master-detail using router

In my blog about passing data to routes I mentioned that you can subscribe to parameters changing over time. In this blog I’ll show you how to do it by implementing master-detail functionality using the router.

Imagine, you have a list of products and, when the user clicks on one of the products, you need to show product details. There are different ways of implementing such functionality, but I’ll implement the use case when the product details functionality is implemented by a separate component that is created by the Angular router. The master part is represented by the list of mobile phones id/description, and the details about selected phone will be displayed by the component ProductDetailComponent that will be created by the router when the method Router.navigate() will be invoked for the first time. The following screen shot was take when the user selected the phone with ID=3. The bottom portion shows the details of this phone rendered by the ProductDetailComponent (on the cyan background) inside the <router-outlet>.

master-detail2

If the user will select another item from the list, its ID will be passed to the route and the respected product details will be displayed. Note that the URL will be change when the user selects different product.

Let’s start with the ProductDetailComponent. Angular router comes with the class ActivatedRoute that among other things stores the data received by the route. If you’ll read the source code of ActivatedRoute you’ll see the following properties there:

/**
* The matrix parameters scoped to this route. 
* The observable will emit a new value when
* the set of the parameters changes.
*/
params: Observable<Params>;

/**
 * The current snapshot of this route.
 */
snapshot: ActivatedRouteSnapshot;

In the previous blog I showed the example of using the snapshot property, which is exactly what the name states – a one time snapshot of the router state. The Router would create an instance of the ProductDetailComponent, where we’d inject the instance of ActivatedRoute and get the id of the phone:

  constructor(private route: ActivatedRoute) {
    this.productID = route.snapshot.params['id'];
  }

If the user would click on the link or invoke navigate() for the first time, the instance of the ProductDetailComponent would be created. But what if the instance of this component has already been created, but the user takes actions that results in multiple invocations of navigate() to the same route? The instance of ProductDetailComponent already exists, its constructor won’t be invoked again, and no new snapshots of the router states will be taken. This is where subscribing to an Observable stream comes in.

  constructor(private route: ActivatedRoute) {

    this.route.params.subscribe(
        params => this.productID = params['id']
    );
  }

The code of the constructor is still invoked once, but now it creates a subscription to the data stream that can be pushed to the route. Of course, if the user will navigate to a different route, the instance of ProductDetailComponent will be destroyed and detached from DOM, and the subscription will be over. But in our application we’ll configure just one route so the subscription will stay alive once created. Below is the entire code of the ProductDetailClass:

import {Component} from '@angular/core';
import {ActivatedRoute} from '@angular/router';

@Component({
  selector: 'product',
  template: `<h3 class="product">Details for product id {{productID}}</h3>`,
  styles: ['.product {background: cyan; width: 200px;} ']
})
export class ProductDetailComponent {
  productID: number;

  constructor(private route: ActivatedRoute) {

    this.route.params.subscribe(
        params => this.productID = params['id']
    );
  }
}

The code that configures the routes, renders the list of products and arranges the navigation is shown next.

import {Component} from '@angular/core';
import {Routes, Router} from '@angular/router';

const routes: Routes = [
    {path: 'product/:id', 
      component: ProductDetailComponent}
];

class Product {
    id: number;
    description: string;
}

@Component({
    selector: 'app',
    template: `
        <ul style="width: 100px;">
           <li *ngFor="let product of products"
            [class.selected]="product === selectedProduct"
            (click) = onSelect(product)>
              {{product.id}} {{product.description}} 
           </li>        
       </ul>
        
        <router-outlet></router-outlet>
    `,
    styles:[`.selected {background-color: cornflowerblue}`]
})
class AppComponent {

    selectedProduct: Product;

    products: Product[] = [
        {id: 1, description: "iPhone 7"},
        {id: 2, description: "Samsung 7"},
        {id: 3, description: "MS Lumina"}
    ];

    constructor(private _router: Router){}

    onSelect(prod: Product): void {
        this.selectedProduct = prod;
        this._router.navigate(["/product", prod.id]);
    }
}

The most interesting steps are the following:

1. We have configured one route that expects the product ID as a parameter:

const routes: Routes = [
    {path: 'product/:id', 
       component: ProductDetailComponent}
];

2. We asked Angular to inject the Router object so we can invoke its method navigate()

    constructor(private _router: Router){}

3. When the user selects a phone from the list, we invoke the click handler passing the selected product to it:

(click) = onSelect(product)>

4. When the product is selected, we want to navigate to the route configured in step 1. If this is the first time the user selects the product, the instance of ProductDetailComponent will be created, otherwise, the existing instance will receive the selected product ID.

onSelect(prod: Product): void {
    this.selectedProduct = prod; // to apply proper styles to the selected product

    this._router.navigate(["/product", prod.id]);
}

Angular uses RxJS and Observables in multiple places, and in this blog I’ve illustrated the use of observable stream with the router.

That’s all there is to it. To see this app in action, check out this plunk.