Avoid Problems by Creating Individual Components in Angular (Sample App Key Learnings #1)

Dhananjay Kumar / Monday, July 17, 2017

Infragistics has a set of nine tutorials for Ignite UI for JavaScript: three to show you how to write apps fast, three to show you how to make sure they run fast, and three about building for the modern web. These all use the Stock Tracker in Angular App, which is created in Angular and uses Ignite UI for JavaScript Angular Components. This application demonstrates the Chart and Grid components' ability to handle large datasets while still allowing for fast rendering and smooth user interaction. (You can download the app here.)

I was the one who developed this app and the lessons that go with it. As I wrote it, I noted several key learnings. Over the next few weeks — beginning in this post — I am going to share a few of these insights.

The first key learning—the one I’ll be talking about today—is this: Create individual components for each control.

The Problem

In the application, we are using various Ignite UI components: Data Chart, Grid and Zoombar, as shown here: 

As you see, there is more than one control in the view.  A common problem could be wrapping all the controls in the single component. Initially, I put all the controls inside AppComponent, causing the following challenges:
  • Tougher to debug: I put all controls in a single component, so there was a single component in the application. This meant debugging tools like Angury didn't create a component tree for better debugging. Since all controls were in the single component, it was tough to find which component was causing the error.
  • Fetching data for all controls in its constructor: There were many controls, and I was fetching data for all controls in the component constructor. Controls were fetching large sets of data from REST API, so Angular was taking more time to execute the component’s constructor. Due to that, the application load time was slow.
  • Error in one control stops the whole AppComponent from rendering in the application.

Initially, the AppComponent template looks like this:

<header>
      <div style="background: black">
          <img src="./images/logo.png">
      div>
  header>
  <ig-data-chart [(options)]="chartOptions" [(dataSource)]="stocks" widgetId="pricechart">
  ig-data-chart>
  <ig-data-chart [(options)]="chartOptions" [(dataSource)]="stocks" widgetId="indicatorchart">
  ig-data-chart>
  <ig-data-chart [(options)]="chartOptions" [(dataSource)]="stocks" widgetId="volumechart">ig-data-chart>
  <ig-zoombar [(options)]="zoombarOptions" widgetId="zoombar">ig-zoombar>
  <ig-grid [(options)]="gridOptions" [(dataSource)]="stocks" [(widgetId)]="gridId">

As it turns out, putting all your controls in a single component is never a good idea. It brings complexity and difficulty while debugging.  Also, it fetches data for all the controls in single component constructor, which delays application load time. Finally, if there is an error in loading data for any controls (like PriceChart, for example), any other controls  (grid, VolumeChart, etc.) will not be rendered.

The Solution

The best approach to solve this problem is to put each control in individual Angular Components.

One of the major building blocks of Angular is Components. The Components are the most basic building block of a UI in an Angular application. An Angular application is a tree of Angular components. Angular components are a subset of directives. Unlike directives, components always have a template and only one component can be instantiated per element in a template. Ideally, Component denotes one UI element on the View. Each Component has its own UI called Template, Styles and code behind. (You can learn more about Components in Angular Essentials, which is available free from Infragistics.) 

Therefore, for our application, each chart and grid should be an individual component. To achieve this, I put each Ignite UI control in separate components and created a project structure as shown here:

As you notice, each control in the HTML is an individual component.

As you notice that, each UI element is now an individual component: one for PriceChart, one for VolumeChart, one for IndicatorChart, etc. Now the template of PriceChartComponent looks like this:

<ig-data-chart [(options)]="chartOptions" [(dataSource)]="stocks" widgetId="pricechart">
ig-data-chart>

Since each component has its own life cycle, now I can fetch data required for PriceChartComponent in the ngOnInit() life cycle hook of PriceChartComponent as shown here: 

ngOnInit() {
    this._appService.getStocks()
        .subscribe(
        stocks => this.stocks = stocks,
        error => this.errorMessage = error);
    this.desiredHeight = 0.22 * (window.screen.height) + "px";
    this.chartOptions = this.getPriceChartOptions();
}

Since, each component is fetching required data in its own lifecycle, application response time is less and debugging is easier. The other advantage is Components can communicate with each other — a capability of Angular.

After creating individual component for each Ignite UI controls, I declared them in the AppModule as shown in the listing below: 

@NgModule({
    imports: [BrowserModule,HttpModule],
    declarations: [AppComponent,
                   IgZoombarComponent,
                   IgDataChartComponent,
                   PriceChartComponent,
                   InfoComponent,
                   IndicatorChartComponent,
                   VolumeChartComponent,
                   IgGridComponent, GridComponent],
    providers: [AppService],
    bootstrap: [AppComponent]
})
export class AppModule { }

Putting each control in separate Components help in better debugging, adding more controls easily, and better load time of application.

Be sure to download the sample application and experiment with it yourself,  and learn more by getting the free Angular Essentials book.

Dhananjay Kumar works as a Developer Evangelist for Infragistics. He is a eight-time Microsoft MVP. You can reach him on Twitter: @debug_mode.