Welcome!

Blog Feed Post

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-detail2https://yakovfain.files.wordpress.com/2016/11/master-detail2.png?w=1520&... 1520w, https://yakovfain.files.wordpress.com/2016/11/master-detail2.png?w=150&h=70 150w, https://yakovfain.files.wordpress.com/2016/11/master-detail2.png?w=300&h... 300w, https://yakovfain.files.wordpress.com/2016/11/master-detail2.png?w=768&h... 768w, https://yakovfain.files.wordpress.com/2016/11/master-detail2.png?w=1024&... 1024w" sizes="(max-width: 760px) 100vw, 760px" />

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.


Read the original blog entry...

More Stories By Yakov Fain

Yakov Fain is a Java Champion and a co-founder of the IT consultancy Farata Systems and the product company SuranceBay. He wrote a thousand blogs (http://yakovfain.com) and several books about software development. Yakov authored and co-authored such books as "Angular 2 Development with TypeScript", "Java 24-Hour Trainer", and "Enterprise Web Development". His Twitter tag is @yfain

Latest Stories
Join IBM November 1 at 21st Cloud Expo at the Santa Clara Convention Center in Santa Clara, CA, and learn how IBM Watson can bring cognitive services and AI to intelligent, unmanned systems. Cognitive analysis impacts today’s systems with unparalleled ability that were previously available only to manned, back-end operations. Thanks to cloud processing, IBM Watson can bring cognitive services and AI to intelligent, unmanned systems. Imagine a robot vacuum that becomes your personal assistant th...
SYS-CON Events announced today that B2Cloud will exhibit at SYS-CON's 21st International Cloud Expo®, which will take place on Oct 31 – Nov 2, 2017, at the Santa Clara Convention Center in Santa Clara, CA. B2Cloud specializes in IoT devices for preventive and predictive maintenance in any kind of equipment retrieving data like Energy consumption, working time, temperature, humidity, pressure, etc.
Today traditional IT approaches leverage well-architected compute/networking domains to control what applications can access what data, and how. DevOps includes rapid application development/deployment leveraging concepts like containerization, third-party sourced applications and databases. Such applications need access to production data for its test and iteration cycles. Data Security? That sounds like a roadblock to DevOps vs. protecting the crown jewels to those in IT.
SYS-CON Events announced today that Cedexis will exhibit at SYS-CON's 21st International Cloud Expo®, which will take place on Oct 31 – Nov 2, 2017, at the Santa Clara Convention Center in Santa Clara, CA. Cedexis is the leader in data-driven enterprise global traffic management. Whether optimizing traffic through datacenters, clouds, CDNs, or any combination, Cedexis solutions drive quality and cost-effectiveness.
Many companies start their journey to the cloud in the DevOps environment, where software engineers want self-service access to the custom tools and frameworks they need. Machine learning technology can help IT departments keep up with these demands. In his session at 21st Cloud Expo, Ajay Gulati, Co-Founder, CTO and Board Member at ZeroStack, will discuss the use of machine learning for automating provisioning of DevOps resources, taking the burden off IT teams.
SYS-CON Events announced today that NetApp has been named “Bronze Sponsor” of SYS-CON's 21st International Cloud Expo®, which will take place on Oct 31 – Nov 2, 2017, at the Santa Clara Convention Center in Santa Clara, CA. NetApp is the data authority for hybrid cloud. NetApp provides a full range of hybrid cloud data services that simplify management of applications and data across cloud and on-premises environments to accelerate digital transformation. Together with their partners, NetApp em...
Is advanced scheduling in Kubernetes achievable? Yes, however, how do you properly accommodate every real-life scenario that a Kubernetes user might encounter? How do you leverage advanced scheduling techniques to shape and describe each scenario in easy-to-use rules and configurations? In his session at @DevOpsSummit at 21st Cloud Expo, Oleg Chunikhin, CTO at Kublr, will answer these questions and demonstrate techniques for implementing advanced scheduling. For example, using spot instances ...
Why Federal cloud? What is in Federal Clouds and integrations? This session will identify the process and the FedRAMP initiative. But is it sufficient? What is the remedy for keeping abreast of cutting-edge technology? In his session at 21st Cloud Expo, Rasananda Behera will examine the proposed solutions: Private or public or hybrid cloud Responsible governing bodies How can we accomplish?
SYS-CON Events announced today that Ryobi Systems will exhibit at the Japan External Trade Organization (JETRO) Pavilion at SYS-CON's 21st International Cloud Expo®, which will take place on Oct 31 – Nov 2, 2017, at the Santa Clara Convention Center in Santa Clara, CA. Ryobi Systems Co., Ltd., as an information service company, specialized in business support for local governments and medical industry. We are challenging to achive the precision farming with AI. For more information, visit http:...
Cloud-based disaster recovery is critical to any production environment and is a high priority for many enterprise organizations today. Nearly 40% of organizations have had to execute their BCDR plan due to a service disruption in the past two years. Zerto on IBM Cloud offer VMware and Microsoft customers simple, automated recovery of on-premise VMware and Microsoft workloads to IBM Cloud data centers.
SYS-CON Events announced today that mruby Forum will exhibit at the Japan External Trade Organization (JETRO) Pavilion at SYS-CON's 21st International Cloud Expo®, which will take place on Oct 31 – Nov 2, 2017, at the Santa Clara Convention Center in Santa Clara, CA. mruby is the lightweight implementation of the Ruby language. We introduce mruby and the mruby IoT framework that enhances development productivity. For more information, visit http://forum.mruby.org/.
With the rise of DevOps, containers are at the brink of becoming a pervasive technology in Enterprise IT to accelerate application delivery for the business. When it comes to adopting containers in the enterprise, security is the highest adoption barrier. Is your organization ready to address the security risks with containers for your DevOps environment? In his session at @DevOpsSummit at 21st Cloud Expo, Chris Van Tuin, Chief Technologist, NA West at Red Hat, will discuss: The top security r...
Smart cities have the potential to change our lives at so many levels for citizens: less pollution, reduced parking obstacles, better health, education and more energy savings. Real-time data streaming and the Internet of Things (IoT) possess the power to turn this vision into a reality. However, most organizations today are building their data infrastructure to focus solely on addressing immediate business needs vs. a platform capable of quickly adapting emerging technologies to address future ...
Cloud applications are seeing a deluge of requests to support the exploding advanced analytics market. “Open analytics” is the emerging strategy to deliver that data through an open data access layer, in the cloud, to be directly consumed by external analytics tools and popular programming languages. An increasing number of data engineers and data scientists use a variety of platforms and advanced analytics languages such as SAS, R, Python and Java, as well as frameworks such as Hadoop and Spark...
SYS-CON Events announced today that Mobile Create USA will exhibit at the Japan External Trade Organization (JETRO) Pavilion at SYS-CON's 21st International Cloud Expo®, which will take place on Oct 31 – Nov 2, 2017, at the Santa Clara Convention Center in Santa Clara, CA. Mobile Create USA Inc. is an MVNO-based business model that uses portable communication devices and cellular-based infrastructure in the development, sales, operation and mobile communications systems incorporating GPS capabi...