© Venkata Keerti Kotaru 2020
V. K. KotaruAngular for Material Designhttps://doi.org/10.1007/978-1-4842-5434-9_13

13. Material Design: Layout

Venkata Keerti Kotaru1 
(1)
Hyderabad, India
 

Angular Material provides components and directives that help position and layout the content. The components adhere to Material Design specifications and provide functionality out of the box.

This chapter describes three often-used components that encapsulate content, cards, tabs, and an accordion with an expandable panel. A card provides view for a single entity. The entity could be an order or customer. Tabs allow switching between entities for each tab. The accordion with an expansion panel displays a list of items.

Material Design: Card

A card is a Material Design construct that visually puts together the content and actions of an entity in the system.

In the sample application, we have used cards, and a superhero is an entity. We show information about a superhero in a card. The form that creates a superhero could be on a card. Figure 13-1 shows a card that creates a superhero.

A card can have the following sections.
  • Card Title: A header or title for the card. Figure 13-1 shows the title Create a new superhero form.

  • Card Subtitle: A subtitle provides brief descriptive information about the purpose of the card. Figure 13-1 describes the form and purpose of the page in the web application.

  • Content : The functionality of the view or the card.

  • Actions : Possible operations of the card content. This section is placed at the bottom of the card. In the sample, the actions are to create a superhero or reset the form.

  • Footer: Descriptive text, information, or warning messages can be placed in the footer. The footer is the last section at the bottom of the card.

  • Card Image: Images and video; provides information about the contents of the card.

../images/475625_1_En_13_Chapter/475625_1_En_13_Fig1_HTML.jpg
Figure 13-1

Create superhero form on a card

Getting Started

To use Angular Material’s card, import the module containing the component. In Listing 13-1, all the Material Design components are encompassed in superheroes-material-design.module.ts.

Import the MatCardModule from the Angular Material repository. Import it into the NgModule (Angular module) encompassing all the Material Design code in the sample application.
import { MatCardModule } from '@angular/material/card';
// Removed code for brevity
@NgModule({
  declarations: [
    // Removed code for brevity
  ],
  imports: [
    MatCardModule,
  ],
  exports: [
  ],
  providers:[]
})
export class SuperheroesMaterialDesignModule { }
Listing 13-1

Import Angular Material Card Module

Using Angular Material Card

Now that we have imported the Angular Material card module, the components that provide the card, card titles, content, and footer are available.

In the sample application, we have already created a component with the form to create a new superhero. We may encapsulate the form in a card. Consider Listing 13-2.
1. <mat-card>
2.  <mat-card-header>
3.    <mat-card-title>
4.      Create a new superhero
5.    </mat-card-title>
6.    <mat-card-subtitle>
7.      A new superhero is born in the system
8.    </mat-card-subtitle>
9.  </mat-card-header>
10.  <mat-card-content>
11.    <form #superheroForm="ngForm">
12.      <!-- Create superhero form goes here.
           Removed code for brevity -->
13.    </form>
14.  </mat-card-content>
15.  <mat-card-actions class="pull-right">
16.    <button mat-stroked-button> Cancel </button>
17.    <button mat-stroked-button [disabled]="!superheroForm.valid"> Save </button>
18.  </mat-card-actions>
19.  <mat-card-footer align="end">
20.    ∗ All superheroes can fly
21.  </mat-card-footer>
22. </mat-card>
Listing 13-2

Create Superhero Form in a Card

The following are the components and directives for creating a card.
  • <mat-card> is the root component for all the card content. It includes the child components.

  • <mat-card-header> is the top section of the card. It may include the following two components: title and subtitle.

  • <mat-card-title> is the title of the card or the superhero form.

  • <mat-card-subtitle> is the subtitle/description of the card or the superhero form.

  • <mat-card-content> is the card content or the superhero form elements.

  • <mat-card-actions> are the buttons that allow the user to create a superhero or reset the form.

  • <mat-card-footer> is the footer text at the bottom of the card.

The mat-card-footer has an align attribute. The value is set to “end”. See line 19 in Listing 13-2. The actions are on the right side of the card. The default value is “start” at which point it is left aligned. Figure 13-2 shows the result.

Angular Material Card with Images

Images on a card are an impressive way to present content to the user. In Figure 13-2, the superhero’s profile is presented in a visually impactful manner. We modify superhero-profile.component.html in the code sample to present data in a card. Similar to Listing 13-3, we add mat-card, the header, and title to the profile component.

Use the following directives to show an avatar and an image on the card.
  • mat-card-avatar: The directive positions the avatar in the header. Add an image to the mat-card-header and the directive mat-card-avatar.

    In Figure 13-2 and Listing 13-3, we use the mat-card-avatar directive on the image element. It is added in <mat-card-header> to show the avatar in the card header, along with the card title and subtitle.

    Consider lines 2 to 6 in the card header. See line 3 for usage of the mat-card-avatar directive.

  • mat-card-image: The directive positions a large image on the card to provide a visual depiction of the content.

    Consider Listing 13-3 (line 7) and Figure 13-2. We use the mat-card-image directive on <img> element between the card header and card content. The directives position and size the images accordingly. It fits into the card content perfectly.
    ../images/475625_1_En_13_Chapter/475625_1_En_13_Fig2_HTML.jpg
    Figure 13-2

    Spiderman profile on a card

1. <mat-card class="half">
2.  <mat-card-header>
3.    <img mat-card-avatar src="/assets/Superhero-logo.png" >
4.    <mat-card-title>{{ name }}</mat-card-title>
5.    <mat-card-subtitle>A superhero, who lives in {{ livesIn }}. </mat-card-subtitle>
6.  </mat-card-header>
7.  <img mat-card-image src="/assets/spiderman.jpg" >
8.  <mat-card-content>
9.    <div>Appeared in the year {{ firstAppearance }}</div>
10.    <div>Lives in {{ livesIn }}</div>
11.    <div ∗ngFor="let power of superpowers">
12.      {{ power }}
13.    </div>
14.    <div ∗ngIf="address">
15.      Meet the superhero at
16.      <div>
17.        {{ address.firstLine }}
18.      </div>
19.      <div>
20.        {{ address.city }}
21.      </div>
22.    </div>
23.  </mat-card-content>
24. </mat-card>
Listing 13-3

Use Material Design Card Components and Directives on Superhero Profile

Note

Image URLs are hard-coded for simplicity. They can be obtained from the model object on the superhero-profile.component.ts file.

Material Design: Tabs

Tabs are often used to organize multiple views on a page. The tab title could be text, or an icon, or both. Tabs show one active view at a time (see Figure 13-3).

The Angular Material component for tabs is confined to the control’s Material Design specifications. It highlights the active tab with an ink bar. The superheroes list in Figure 13-3 animates as we switch between tabs.

Note

Remember, BrowserAnimationsModule was imported into SuperheroesMaterialDesignModule. We can limit animations by switching to NoopAnimationModule instead.

../images/475625_1_En_13_Chapter/475625_1_En_13_Fig3_HTML.jpg
Figure 13-3

Material Design tabs

Getting Started

To use Angular Material’s tabs, import the module containing the component. In Listing 13-4, all the Material Design components are encompassed in superheroes-material-design.module.ts.

Import MatTabsModule from the Angular Material repository into the NgModule (Angular module) encompassing all the Material Design code in the sample application.
import { MatTabsModule } from '@angular/material/tabs';
// Removed code for brevity
@NgModule({
  declarations: [
  ],
  imports: [
    // removed code for brevity
    MatTabsModule,
  ],
  exports: [],
  providers: [HitCounter]
})
export class SuperheroesMaterialDesignModule { }
Listing 13-4

Import Tabs Module

To add tabs to the sample application, consider creating a new component. Run the Angular CLI command in Listing 13-5 to create a component in the Superheroes-material-design module.
ng g component superheroes-material-design/tab-sample
Listing 13-5

Create a New Component for Tabs

The Angular CLI command in Listing 13-5 updates the declarations array in the superheroes-material-design module. The component is available to use within SuperheroesMaterialDesignModule. We have taken advantage of the scaffolded import (automatically) with many components created using Angular CLI.

Sometimes, however, we want to use the component outside SuperheroesMaterialDesignModule. In the tabs’ scenario, we reference it in the root AppComponent, which is in a different module—AppModule; hence, we export it from the SuperheroesMaterialDesign module, which allows us to use the component outside the current module. Lines 12 to 14 in Listing 13-6 export one or more components from the module. Line 2 and lines 5 to 7 are updated by Angular CLI when the component is created.
1. import { MatTabsModule } from '@angular/material/tabs';
2.    import { TabSampleComponent } from './tab-sample/tab-sample.component';
3. // Removed code for brevity
4. @NgModule({
5.  declarations: [
6.             TabSampleComponent,
7. ],
8.  imports: [
9.    // removed code for brevity
10.    MatTabsModule,
11.  ],
12.  exports: [
13.    // removed code for brevity
14.          ,TabSampleComponent
  ],
  providers:[]
})
export class SuperheroesMaterialDesignModule { }
Listing 13-6

Import Tabs Module

Using Angular Material Tabs

So far, we have imported the required module to use the tabs and created a new component (TabSampleComponent), in which the tabs code can be written.

Let’s create the tabs. In tab-sample.component.html (the template file for TabSampleComponent), use the <mat-tab-group> and <mat-tab> components. The <mat-tab-group> component encapsulates multiple tabs. It is the parent component for all tabs. Each tab is represented by <mat-tab>.

The code in Listing 13-7 is for tab-sample.component.html. We create two tabs with <mat-tab> components and the child elements under <mat-tab-group>.
<div>
  <mat-tab-group>
    <mat-tab label="Superheroes List">
      <app-superhero-list></app-superhero-list>
    </mat-tab>
    <mat-tab label="Create a Superhero">
        <app-create-superhero></app-create-superhero>
    </mat-tab>
  </mat-tab-group>
</div>
Listing 13-7

Using Tabs

Components that list superheroes and create a superhero are child elements within each <mat-tab>. The first tab shows the superhero list, and the second tab shows the create superhero component.

Note the label attribute on <mat-tab>. The text input into the label is the tab title (see Figure 13-3).

So far in the sample application, we have created a new component for the tab sample and created two tabs under it. The component was exported from the superhero-material-design module. It has not been used anywhere. Consider using it in app.component.html, the root component (see Listing 13-8).
<app-superhero-toolbar (menuClick)="toggleSidenav($event)">
  <!-- removed toolbar code for brevity -->
</app-superhero-toolbar>
<app-tab-sample>
</app-tab-sample>
Listing 13-8

AppComponent at Root, Referencing Tabs

Note

For this sample, we use tabs instead of left navigation and workspace. app-tab-sample is the selector for TabSampleComponent; hence, it is used in the HTML template.

While we used the label attribute for a text label (see Listing 13-9), for rich text that includes an icon in the tab label, consider using the mat-tab-label directive. Listing 13-9 uses an <ng-template> with <mat-icon>. See lines 3 to 6 and 9 to 11.
1.  <mat-tab-group>
2.    <mat-tab >
3.      <ng-template mat-tab-label>
4.             <mat-icon>list</mat-icon> Superheroes
5.          </ng-template>
6.      <app-superhero-list></app-superhero-list>
7.    </mat-tab>
8.    <mat-tab >
9.        <ng-template mat-tab-label>
10.                         <mat-icon>create</mat-icon> Add Superhero
11.                   </ng-template>
12.        <app-create-superhero></app-create-superhero>
13.    </mat-tab>
14.  </mat-tab-group>
Listing 13-9

Tab Labels with Rich Text

Figure 13-4 shows the result.
../images/475625_1_En_13_Chapter/475625_1_En_13_Fig4_HTML.jpg
Figure 13-4

Rich text for the tab title

Router Integration with Tabs

We have created two tabs. They load two different components or views without updating the route. The URL does not change as the users switch tabs. However, we might need router integration to let users bookmark a tab. Moreover, if there are a large number of tabs, it is good practice to map a route to each tab.

For Angular router integration, consider Listing 13-10, in which we modify the TabSampleComponent template to use the following directives.
  • mat-tab-nav-bar: Creates a tab group with router links. Use on a parent component that encapsulates tabs that are router links.

  • mat-tab-link: A router link with the view of a tab. Use mat-tab-link along with routerLink.

<nav mat-tab-nav-bar>
  <a routerLink="/create-hero" mat-tab-link>
      Create
  </a>
  <a routerLink="/heroes" [queryParams]="{sortOrder: 'descending'}" mat-tab-link >
      List (Order Descending)
  </a>
  <a routerLink="/heroes" [queryParams]="{sortOrder: 'ascending'}"  mat-tab-link>
      List (Order Ascending)
  </a>
</nav>
Listing 13-10

Router Integration with Tabs

Note the routerLink directive on the anchor elements. As the user switches tabs, it updates <router-outlet> in AppComponent. Figure 13-5 shows the results. Note the URL reflects the selected tab.
../images/475625_1_En_13_Chapter/475625_1_En_13_Fig5_HTML.jpg
Figure 13-5

Tabs integrated with router

For the router to work, RouterModule from @angular/router needs to be imported. Remember, in Chapter 11 we used app-routing.module for the routing logic.

Listing 13-11 uses the router. Import AppRoutingModule from app-routing.module.ts. On SuperheroesMaterialDesignModule, to the imports list, add AppRoutingModule.
import { AppRoutingModule } from '../app-routing.module';
// Removed code for brevity
@NgModule({
  declarations: [
    // Removed code for brevity
  ],
  imports: [
    AppRoutingModule,
  ],
  exports: [/∗ Removed code for brevity ∗/ ],
  providers:[ /∗ Removed code for brevity ∗/],
  entryComponents: [/∗ Removed code for brevity ∗/]
})
export class SuperheroesMaterialDesignModule { }
Listing 13-11

App Routing Module Import for Router Integration with Tabs

Expansion Panel

The Angular Material expansion panel with the accordion allows the showing of a long list of entities in a concise manner. In a large list, the user can collapse many items and expand only the entities that she prefers to focus on. The remaining data elements are collapsed and hidden, making the view easy to comprehend.

Figure 13-6 shows the various aspects of an accordion and the expansion panel. The accordion holds a list of expansion panels.
../images/475625_1_En_13_Chapter/475625_1_En_13_Fig6_HTML.jpg
Figure 13-6

Expansion panel

Getting Started

To use Angular Material’s expansion panel, import the module containing the component. In Listing 13-12, all the Material Design components are encompassed in superheroes-material-design.module.ts.

Import MatCardModule from the Angular Material repository into the NgModule (Angular module) encompassing all the Material Design code in the sample application.
import { MatExpansionModule } from '@angular/material/expansion';
// Removed code for brevity
@NgModule({
  declarations: [
    // Removed code for brevity
  ],
  imports: [
    MatExpansionModule,
  ],
  exports: [
  ],
  providers:[]
})
export class SuperheroesMaterialDesignModule { }
Listing 13-12

Import Angular Material Expansion Panel

To add an expansion panel to the sample application, consider creating a new component. Run the Angular CLI command in Listing 13-13 to create a component in the Superheroes-material-design module.
ng g component superheroes-material-design/superheroes-expandable-list
Listing 13-13

Create a New Component for Expansion Panel

Angular CLI updates the declarations array in the superheroes-material-design module. We require it to reference the router module (app-routing.module.ts). We anticipate using the component outside SuperheroesMaterialDesignModule, in which it was created and declared, so export it from the module (see Listing 13-14).
import { MatExpansionModule } from '@angular/material/expansion';
import { SuperheroesExpandableListComponent } from './superheroes-expandable-list/superheroes-expandable-list.component';
// Removed code for brevity
@NgModule({
  declarations: [
      SuperheroesExpandableListComponent
    // Removed code for brevity
  ],
  imports: [
    MatExpansionModule,
  ],
  exports: [
      SuperheroesExpandableListComponent
  ],
  providers:[]
})
export class SuperheroesMaterialDesignModule { }
Listing 13-14

Import Angular Material Expansion Panel

To show the component at a route, update the router configuration. In Listing 13-15, it is in app-routing.module.ts.
import { SuperheroesExpandableListComponent } from './superheroes-material-design/superheroes-expandable-list/superheroes-expandable-list.component';
const routes: Routes = [
  {
    path: "heroes-accordion",
    component: SuperheroesExpandableListComponent
  },
  // Removed code for brevity
];
@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
Listing 13-15

Router Configuration For Expansion Panel

To see the component in action, navigate to the newly configured url /heroes-accordion.

Using the Expansion Panel

Now that the required modules are imported and the sample application is setup, to use expansion panel, consider the following directives.
  • mat-accordion: Uses the accordion as the root component for the list of expansion panels.

  • mat-expansion-panel: Each expandable area under the accordion is an expansion panel. It is the child component of the accordion. A panel can be in one of the two states: expanded or collapsed.

  • mat-expansion-panel-header: The header is the title section of the expansion panel. This section always shows minimal information about the panel, even in a collapsed state. Typically, clicking the header section expands to show more information about the panel. It is a child component of mat-expansion-panel (see Figure 13-6).

  • mat-panel-title: The title text or section of the panel. It is a child component of mat-expansion-panel-header. See Figure 13-6.

  • mat-panel-description: Provides descriptive information about the panel. It is a child component of mat-expansion-panel-header (see Figure 13-6).

  • mat-action-row: Actions are typically buttons or links that perform operations on the panel or the entity in the panel. The buttons show in an expanded state and hide with the collapsed panel. It is a child component of mat-expansion-panel.

  • MatExpansionPanelContent: Typically, the whole list of panels under the accordion load upfront. To delay loading the panel only on Click to expand, use the MatExpansionPanelContent directive.

Listing 13-16 is the template used in the newly created superheroes-expandable-list.component.
1. <mat-accordion>
2.  <mat-expansion-panel ∗ngFor="let hero of heroes">
3.    <mat-expansion-panel-header>
4.      <mat-panel-title>
5.        {{ hero.name }}
6.      </mat-panel-title>
7.      <mat-panel-description>
8.        {{ hero.details }}
9.      </mat-panel-description>
10.    </mat-expansion-panel-header>
11.    <div>Lives in {{hero.country}}</div>
12.    <div>
13.      Superhero
14.      <span ∗ngFor="let power of hero.specialPowers">
15.        {{ power }}&nbsp;
16.      </span>
17.    </div>
18.    <div>
19.        Likes to eat
20.        <span ∗ngFor="let food of hero.favFood">
21.          {{ food }}
22.        </span>
23.      </div>
24.    <mat-action-row>
25.        <button mat-stroked-button> Fly </button>
26.        <button mat-stroked-button> Shoot lazers </button>
27.    </mat-action-row>
28.  </mat-expansion-panel>
29. </mat-accordion>
Listing 13-16

Using Material Design Expansion Panel

Note ∗ngFor in the expansion panel in line 2. We iterate through list of superheroes. Listing 13-17 is the TypeScript file component with a list of mock hero objects.
import { Superhero } from '../models/superhero';
@Component({ /∗ removed code for brevity ∗/ })
export class SuperheroesExpandableListComponent implements OnInit {
  private heroes: Array<Superhero> = [
    {
      name: "Chhotta Bheem",
      email: "[email protected]",
      details: "A hero in Dholakpur village",
      country: "India",
      cardImage: "spiderman.jpg",
      specialPowers: ["is strong"],
      favFood: ["Laddu"],
      isExpanded: true,
    },
    // removed code for brevity
  ];
  constructor() { }
  ngOnInit() {}
}
Listing 13-17

TypeScript File Component with Heroes Objects Defined

Each superhero is shown in a single mat-expansion-panel element. It is similar to the list screen in earlier samples except that the expansion panel allows the user to focus on one of the rows for more information (by expanding just one item).

Typically, the user clicks a panel to expand. To show one of the panels expanded by default, use the expanded input attribute and set the value to true (see line 2 in Listing 13-18).
1. <mat-accordion>
2.   <mat-expansion-panel ∗ngFor="let hero of heroes" [expanded]="hero.isExpanded">
3.    <mat-expansion-panel-header>
4.      <!-- removed code for brevity -->
5.    </mat-expansion-panel-header>
6.      <!-- removed code for brevity -->
7.      <mat-action-row>
8.      <!-- removed code for brevity -->
9.      </mat-action-row>
10. </mat-expansion-panel>
Listing 13-18

Expand Panel by Default

We used data binding to expand a panel on load. The accordion allows only one of them to open. As another panel is expanded, the open item collapses.

In Listing 13-19, just one item’s isExpanded is expected to be true. It is part of the hero object, which is an item in the heroes array. If more than one objects’ isExpanded is true, the last value takes effect.

To let more than one item expand at a time, use the multi input attribute on mat-accordion. Listing 13-19 shows all the panels open on load. See the highlighted code in line 1 and line 2.
1. <mat-accordion multi="true">
2.   <mat-expansion-panel ∗ngFor="let hero of heroes" expanded="true">
3.    <mat-expansion-panel-header>
4.      <!-- removed code for brevity -->
5.    </mat-expansion-panel-header>
6.      <!-- removed code for brevity -->
7.      <mat-action-row>
8.      <!-- removed code for brevity -->
9.      </mat-action-row>
10. </mat-expansion-panel>
Listing 13-19

All Panels Expanded

Conclusion

The chapter discussed three Angular Material components: cards, tabs, and the accordion with an expansion panel. The Angular Material card showcases an entity, categorized with a title (within the header), content, footer, and actions.

The chapter also covered importing the Angular Material tabs module. We created a separate component using Angular CLI that showed tabs for a create component and a list of superheroes. The expansion panel and accordion were explained. The component shows a list of superheroes that is expandable or collapsible as the user clicks a section.

Exercise

In the dinosaur application, create a new component to show a list of dinosaurs. Use expansion panels for the list. Expand the first item in the list on load.

Create a new tabbed component. Add the newly created dinosaur list as the first tab. Create additional tabs that show the add dinosaur and the dinosaur details components.

References

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.229.113