Skip to content
  • iImagine
  • Register
  • Log In

Web Development School

Learning made easy.

  • Books
    • Beginning Web Development with ASP.Net Core & Client-Side Technologies
      • TOC
      • Part 1
        • Chapter 1: Static HTML – Designing the landing page
      • Part 2
        • Chapter 2: ASP.Net Core – Let’s talk Dynamic
        • Chapter 3: Introduction to ASP.Net Core MVC
          [ASP.Net Core v9]
      • Part 4
        • Chapter 7: Using Server Side & Client Side technologies together
          [ASP.Net Core v7 & Angular 15]
  • Environment Setup
    • Installing Angular
    • Installing Visual Studio 2022
    • Installing SQL Server 2022 Express
    • Installing Postman
    • Installing Git for Windows
  • Blog
  • iImagine WebSolutions
  • Events
  • Learning Videos
  • Toggle search form

MatCheckbox: Category Search UI

In the last module we set up a search panel area. Let’s start filling it in.


In Chapter 01 we created a side panel where we could search for vehicles by category; Car, Truck, or Jeep. The screenshot below is what it looks like.

In the screen shot above the buttons are styled with Bootstrap since that is the CSS library we used in Chapter 1. Since we are using the Angular Material component library now, let’s try something a little different. Let’s set up the category search with some MatCheckbox components.

In chapter 1 we could select ‘All’, ‘Cars’, ‘Trucks’, or ‘Jeeps’. But we could not select both Cars and Trucks, or Trucks and Jeeps. In this new UI will be able to select any combination of categories as we soon shall see. The screen shot below shows an example where the combination of Trucks and Jeeps are selected.

In the screenshot above, only Truck and Jeep are selected. So the All category checkbox instead of having a checkmark shows shows a dash. This is called the indeterminate state. The other states are checked and unchecked; checked being when Car, Truck, and Jeep are all selected, and unchecked being when none of the selections are checked. This is the interface we are going to create. So let’s get to work!

Note: The pathway I am using for development in this module is:
C:\Development\FredsCars\FullStack\Module20.
Table Of Contents
  1. Import MatCheckboxModule
  2. Create an ASP.Net Core API Controller
  3. Test the VehicleTypes web service
  4. Define the VehicleType Interface
  5. Define the Category Interface
  6. Modify the Vehicles component TypeScript: Create the Categories
  7. Modify the Vehicles component HTML
    • Import FormsModule
    • CSS for list-items
  8. Test the Category UI
    • Check a subcategory
    • Check the All checkbox
    • Uncheck the All checkbox
  9. Removethe debug settings
  10. What's Next

Import MatCheckboxModule

Open angular-material.module.ts and make the code modifications below in bold blue font.

FredsCars/src/app/angular-material.module.ts

import { NgModule } from '@angular/core';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatIconModule } from '@angular/material/icon';
import { MatButtonModule } from '@angular/material/button';
import { MatTableModule } from '@angular/material/table';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatSortModule } from '@angular/material/sort';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatCheckboxModule } from '@angular/material/checkbox';

const angularMatModules = [
  MatToolbarModule,
  MatIconModule,
  MatButtonModule,
  MatTableModule,
  MatProgressSpinnerModule,
  MatPaginatorModule,
  MatSortModule,
  MatSidenavModule,
  MatCheckboxModule

]

@NgModule({
  imports: [
    angularMatModules
  ],
  exports: [
    angularMatModules
  ]
})
export class AngularMaterialModule { }

In the code above we are once again simply importing the Angular Material module of the component we want to use, in this case MatCheckbox.

Create an ASP.Net Core API Controller

In the new UI shown above, we are going to want to fetch the category names dynamically just like we do the actual vehicle results. And we already made the decision earlier on when we created the Vehicles ASP.Net Core API controller that although status (New or Used) can be an enum, we are going to store VehicleTypes in the database. So we are going to create a VehicleTypes controller to return the Categories from a database on the ASP.Net Core side.

Create a file called VehicleTypesController.cs in the FredsCarsAPI/Controllers folder and fill it with the contents below.

FredsCarsAPI/Controllers/VehicleTypesController.cs

using FredsCarsAPI.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace FredsCarsAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class VehicleTypesController : ControllerBase
    {
        [HttpGet]
        public IEnumerable<VehicleType> GetVehicles()
        {
            var vehicleTypes = new List<VehicleType>
            {
                new VehicleType { Id = 1, Name = "Car" },
                new VehicleType { Id = 2, Name = "Truck" },
                new VehicleType { Id = 3, Name = "Jeep" }
            };

            return vehicleTypes;
        }
    }
}

In the code above we simply define an HTTP GET rest service called VehicleTypes. In the GET method we define a variable called vehicleTypes of type List<VehicleType> and fill it with static VehicleType objects. Rest assured we will make all of our data dynamic and pull from a database in upcoming modules. But for now this will do the trick and let us continue developing our Angular application.

Test the VehicleTypes web service

Run the FredsCarsAPI project in debug mode by right clicking on FredsCarsAPI in Solution Explorer and selecting Debug --> Start New Instance.

Open Postman and create a GET request for the following URL.

https://localhost:40443/api/VehicleTypes

If you haven’t installed Postman yet you can find a tutorial for installing and running Postman at Installing Postman on my blog.

Hit Send to execute the request and the JSON results should look like the following.

In the screenshot above you can see we have returned a JSON array of Vehicle objects from our web service.

Define the VehicleType Interface

The next step is to define a TypeScript interface for VehicleType on the Angular side just as we did for Vehicles.

Create a file called vehicleType.ts in the FredsCars/src/app/vehicles folder and fill it with the contents below:

FredsCars/src/app/vehicles/vehicleType.ts

export interface VehicleType {
  id: number;
  name: string;
}

Define the Category Interface

Now that we have our web service and client-side interface in place we can fetch VehicleType data and lay out our checkboxes right? Well, almost. Our C# VehicleType object and Angular VehicleType interface both have two properties: id, and name. But for the checkboxes we to also need to track whether each checkbox is selected. And we need a way to structure our categories so that the All checkbox is considered the main category. And the Car, Truck, and Jeep categories are considered subcategories. This will let us set whether the All checkbox is in the indeterminate, checked, or unchecked state we talked about earlier looking at the new UI screenshot.

So let’s tackle that right now. Open up the vehicleType.ts file in the Angular application and modify it with the code below.

FredsCars/src/app/vehicles/vehicleType.ts

export interface VehicleType {
  id: number;
  name: string;
}

export interface Category {
  id: number;
  name: string;
  selected: boolean;
  categories?: Category[]
}

In the code above we have added a new Category interface much like our VehicleType interface. But Category contains an extra property called selected of type boolean to allow us to track whether each checkbox is selected or not. It also contains a property called categories of type Category Array to store our Car, Truck, and Jeep subcategories.

Modify the Vehicles component TypeScript: Create the Categories

Now that we have a Category interface to work with, we can create a variable of that type, fetch all VehicleTypes from our new API service, transform them into Categories, and store them in the variable’s categories array.

Open the vehicles.component.ts file and make the modifications below in bold blue font.

FredsCars/src/app/vehicles/vehicles.component.ts

import { Component, OnInit, ViewChild } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Vehicle } from './vehicle';
import { environment } from '../../environments/environment';
import { MatTableDataSource } from '@angular/material/table';
import { MatPaginator } from "@angular/material/paginator";
import { MatSort } from "@angular/material/sort";
/*  Import */
import { Category, VehicleType } from './vehicleType';

@Component({
  selector: 'app-vehicles',
  templateUrl: './vehicles.component.html',
  styleUrls: ['./vehicles.component.scss']
})
export class VehiclesComponent implements OnInit {
  // debug JSON var for HTML
  public json = JSON; 
  public vehicles: MatTableDataSource<Vehicle>

  columnsToDisplay: string[] = ['id', 'vehicleType', 'status', 'year', 'make', 'model', 'color', 'price'];

  @ViewChild(MatPaginator) paginator!: MatPaginator;
  @ViewChild(MatSort) sort!: MatSort;

  categoryAll: Category = {
    id: 0,
    name: 'All',
    selected: false,
    categories: []
  };
  allCategoriesSelected: boolean = false;
  
  constructor(private http: HttpClient) {
    this.vehicles = new MatTableDataSource<Vehicle>();
  }

  ngOnInit() {
    // get vehciles
    this.http.get<Vehicle[]>(environment.baseUrl + 'api/vehicles').subscribe(result => {
       this.vehicles.data = result;
    }, error => console.error(error));
    // get vehicleTypes and transform into search catgories
    this.http.get<VehicleType[]>(environment.baseUrl + 'api/vehicleTypes').subscribe(result => {
      result.forEach(vt => {
        this.categoryAll.categories?.push(
          {
            id: vt.id,
            name: vt.name,
            selected: false
          }
        );
      }) 
    }, error => console.error(error));
  }

  ngAfterViewInit() {
    this.vehicles.paginator = this.paginator;
    this.vehicles.sort = this.sort;
  }

  /*** Categogry Search Checkbox methods ***/
  public someSearchCategoriesSelected(): boolean {
    return this.categoryAll.categories!.filter(cat =>
      cat.selected).length > 0 && !this.allCategoriesSelected;
  }

  setAllCategoriesSelected(checked: boolean) {
    this.allCategoriesSelected = checked;
    this.categoryAll.selected = checked;
    this.categoryAll.categories!.forEach(cat =>
      (cat.selected = checked));
  }

  updateAllCategoriesSelected() {
    var allSelected: boolean =
      this.categoryAll.categories!.every(cat =>
        cat.selected);

    this.allCategoriesSelected = allSelected;
    this.categoryAll.selected = allSelected;     
      
  }
  /*** End Categogry Search Checkbox methods ***/
}

Let’s take a few minutes to look at the new code sprinkled into the Vehicles component TypeScript.

The first thing we did at the top of the TypeScript was import the new Category and already existing VehcileType interfaces so we can use them below in the code.

Next in the top line of the VehcilesComponent class we create a variable called json of type JSON. We will use the JSON object on the front end to set up a debug panel so we can see the state of the Angular Checkboxes model update live while we test checking and unchecking combinations of checkboxes.

public json = JSON;

Then we create a variable called categoryAll of type Category, the interface we just created.
The categoryAll variable will have an id of 0 representing all categories chosen, a name of All, and initially have a selected value of false, or unchecked. The categories array property is initialized to an empty array which we will fill with VehicleTypes transformed to Categories in ngOnInit.

categoryAll: Category = {
    id: 0,
    name: 'All',
    selected: false,
    categories: []
  };

We also create a variable called allCategoriesSelected of type boolean. If this variable is true, then the All checkbox should be checked. It starts off initialized to false.

allCategoriesSelected: boolean = false;

In ngOnInit, we add a second HTTP Get call to the new VehicleTypes API service. We subscribe to the returned Observable which is an array of VehicleType. Then we loop through the VehicleTypes (Car, Truck, and Jeep) transforming each one into a Category and pushing it onto the categoryAll.categories subcategory array.

// get vehicleTypes and transform into search catgories
this.http.get<VehicleType[]>(environment.baseUrl + 'api/vehicleTypes').subscribe(result => {
  result.forEach(vt => {
	this.categoryAll.categories?.push(
	  {
		id: vt.id,
		name: vt.name,
		selected: false
	  }
	);
  }) 
}, error => console.error(error));

At the bottom of the TypeScript we have three methods to help manage our Category Checkbox model and states.

The first method is called someSearchCategoriesSelected. This method helps us figure out if only some of the Categories, but not all, are selected by using the Array.filter() method on the categoryAll.categories property to check if it has at least one category selected but not all categories. We know whether all categories are selected by checking the new allCategoriesSelected variable we just created.

public someSearchCategoriesSelected(): boolean {
    return this.categoryAll.categories!.filter(cat =>
      cat.selected).length > 0 && !this.allCategoriesSelected;
  }

The second method is called setAllCategoriesSelected. This method takes in a parameter called checked of type boolean. This method will receive an event whenever the All Checkbox is checked or unchecked, true or false respectively, and set allCategoriesSelected (needed above in someSearchCategoriesSelected) and the categoryAll.selected property. Then we loop through the subcategories in the categoryAll.categories property (updating the Angular live data model) to true or false.

setAllCategoriesSelected(checked: boolean) {
    this.allCategoriesSelected = checked;
    this.categoryAll.selected = checked;
    this.categoryAll.categories!.forEach(cat =>
      (cat.selected = checked));
  }

The third and final method is called updateAllCategoriesSelected. This method will be fired everytime a user checks or unchecks one of the subcategories; Car, Truck, or Jeep. It has a local variable called allSelected of type boolean. As users select and unselect the Car, Truck, and Jeep categories, the allSelected local variable gets set to the result of a lamda expression passed to the every() method of the categoryAll.categories property. The every() expression returns true if the expression passed to it is true for every element, in this case every subcategory is selected, and false otherwise. Finally we update allCategoriesSelected and the categoryAll.selected property just as we do in the setAllCategoriesSelected method above.

updateAllCategoriesSelected() {
    var allSelected: boolean =
      this.categoryAll.categories!.every(cat =>
        cat.selected);

    this.allCategoriesSelected = allSelected;
    this.categoryAll.selected = allSelected;     
      
  }

This wasn’t really a lot of code we just added except for the three helper methods at the end. They may seem a little difficult to understand at this point, especially without first having modified and studied the HTML in the template. But once we do that we will see it all makes sense. And, we will see the power of databinding MatCheckbox attributes and events to these new variables and helper methods.

Modify the Vehicles component HTML

Now that we have done the preparation in the TypeScript to support the checkbox selections and the categories portion of the Angular data model, we can finally build the Categories selection UI with MatCheckbox.

Open the vehicles.component.html file and make the modifications below in blue bold font.

FredsCars/src/app/vehicles/vehicles.component.html

<mat-sidenav-container autosize>
  <mat-sidenav mode="side" #sidenav opened>
    <div style="margin-right: 10px;">
      <p><b>Search Panel</b></p>
      <hr />
      <p><b>Categories</b></p>
      <mat-checkbox color="primary"
          [checked]="allCategoriesSelected"
          [indeterminate]="someSearchCategoriesSelected()"
          (change)="setAllCategoriesSelected($event.checked)">
        {{ categoryAll.name }}
      </mat-checkbox>
      <ul>
        <li *ngFor="let category of categoryAll.categories">
          <mat-checkbox color="accent"
              [(ngModel)]="category.selected"
              (ngModelChange)="updateAllCategoriesSelected()">
            {{category.name}}
          </mat-checkbox>
        </li>
      </ul>
      <!-- debug -->
      
      <b>categoryAll:</b><br />
      {{ categoryAll.selected }}<br />
      <b>Categories:</b>
      <ul>
        <li *ngFor="let category of categoryAll.categories">
          {{category.name}}: {{ category.selected}}
        </li>
      </ul>
      
      <!-- end debug-->
    </div>
  </mat-sidenav>

  <mat-sidenav-content>
    <p *ngIf="!vehicles">
      <mat-spinner style="margin: 0 auto;"></mat-spinner>
    </p>

    <!-- existing content -->

    <!-- ToDo: Change pageSize back to 5-->
    <mat-paginator [pageSize]="10" [pageSizeOptions]="[3, 5, 10]">
    </mat-paginator>   
 
  </mat-sidenav-content>
</mat-sidenav-container>

Import FormsModule

In the html above we use ngModel to implement two way databinding to bind each subcategory’s selected property to the data model. We’ll talk more about this when we go back and inspect the html. But, before we can run the application and see what it looks like we need to import FormsModule in order for ngModel to work.

Open the app.module.ts file and make the modifications below.

FredsCars/src/app/app.module.ts

import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';

import { AppComponent } from './app.component';
import { VehiclesComponent } from './vehicles/vehicles.component';
import { WelcomeComponent } from './welcome/welcome.component';
import { NavMenuComponent } from './nav-menu/nav-menu.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AngularMaterialModule } from './angular-material.module';
import { HeaderComponent } from './header/header.component';
import { FooterComponent } from './footer/footer.component';
import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    AppComponent,
    VehiclesComponent,
    WelcomeComponent,
    NavMenuComponent,
    HeaderComponent,
    FooterComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    AngularMaterialModule,
    FormsModule

  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

CSS for list-items

For the last tweak before we run the application we need to remove the bullet points from the category list-items. We just want the indenting a list-item gives, not the bullet points. Open the vehicles.component.scss file and make the following modifications.

FredsCars/src/app/vehicles/vehicles.component.scss

/* existing code */

li {
  list-style: none;
}

Now if we run the application, it should look similar to the following screenshot.

Let’s inspect the vehicles component html above and then we’ll go through some examples of how it works.

The first thing we did was add the opened attribute to the mat-side-nav element.

<mat-sidenav mode="side" #sidenav opened>

This attribute starts the SideNav off in the opened position so we don’t have to keep clicking the search glass icon to open the SideNav back up every time we make a change and hot reload reloads the browser. We will remove this attribute at the end of the module.

The next thing we did was add a Categories label in bold tags and a mat-checkbox element.

<hr />
<p><b>Categories</b></p>
<mat-checkbox color="primary"
  [checked]="allCategoriesSelected"
  [indeterminate]="someSearchCategoriesSelected()"
  (change)="setAllCategoriesSelected($event.checked)">
{{ categoryAll.name }}
</mat-checkbox>

The mat-checkbox element has it’s color attribute set to primary so it will have the indigo-pink theme’s primary color when checked. We bind the checked attribute to the allCategoriesSelected variable we manage in the TypeScript. The indeterminate attribute gets bound to our someSearchCategoriesSelected() checkbox helper method. And we bind the change event to our setAllCategoriesSelected() checkbox helper method. When a user checks or unchecks the All checkbox, the change event is fired, and an event with the All checkbox’s checked state is passed as a parameter to setAllCategoriesSelected(). Finally we lay out the label text of the checkbox using one way databinding to display the name property of categoryAll which we initialized to ‘All’ in the TypeScript.


After the All checkbox, we lay out an unordered list of mat-checkbox to represent the subcategories; Car, Truck, and Jeep.

<ul>
	<li *ngFor="let category of categoryAll.categories">
	  <mat-checkbox color="accent"
		  [(ngModel)]="category.selected"
		  (ngModelChange)="updateAllCategoriesSelected()">
		{{category.name}}
	  </mat-checkbox>
	</li>
</ul>

Here we use the ngFor structural directive to lay out a list-item for each subcategory. Each list-item contains as its contents a mat-checkbox element. And each mat-checkbox has it’s color attribute set to accent so it will have the indigo-pink theme’s accent color when checked. The ngModel attribute is bound to each subcategory’s selected property creating two way databinding. This creates the affect where when the user clicks the Car, Truck, or Jeep checkboxes, their selected property is updated in the Angular live data model. And when our setAllCategoriesSelected() helper method updates all the subcategory selected properties (as a result of the user checking the All checkbox), the subcategory checkboxes gets checked or unchecked depending on the update to the model. The ngModelChange event is bound to our updateAllCategoriesSelected() helper method. ngModelChange is the output of ngModel. So when the model changes it calls our updateAllCategoriesSelected() helper. The label text of each checkbox is set with {{category.name}}, the name property of each subcategory, as the value of the mat-checkbox element.

In the last portion we create a little debug panel so we can watch the data model update as we check and uncheck categories.

<!-- debug -->
      
  <b>categoryAll:</b><br />
  {{ categoryAll.selected }}<br />
  <b>Categories:</b>
  <ul>
	<li *ngFor="let category of categoryAll.categories">
	  {{category.name}}: {{ category.selected}}
	</li>
  </ul>

<!-- end debug-->

Our debug panel code is very similar to how we lay out the subcategory checkboxes. First we display the categoryAll.selected property so we can view the state of the All checkbox in the datamodel as we check and uncheck it. Then we use ngFor to lay out the category name and selected state for each subcategory checkbox so we can view the selected state for Car, Truck, and Jeep live in the datamodel as the user checks and unchecks them.

One last thing we did was set the default pageSize of the MatPaginator to 10.

<!-- ToDo: Change pageSize back to 5-->
<mat-paginator [pageSize]="10" [pageSizeOptions]="[3, 5, 10]">
</mat-paginator>

The reason we did this is because with pageSize set at 5 rows, the vehicles table does not create enough height for the debug panel and a vertical scrollbar shows up for the MatSidenav sidebar. We don’t want to have to keep scrolling down to view the data model when we make changes.

Test the Category UI

Now that we have everything in place, let’s run through some examples to test the Categories selection UI.

Check a subcategory

Let’s start off by clicking one subcategory. Click the Truck checkbox and your browser should look similar the screenshot below.

In the screenshot above, by clicking the Truck checkbox, the selected property of Truck in categoryAll.categories in the Typescript becomes true which we can see in our debug panel near the bottom. Also since some of the subcategories are selected (at least one), the All checkbox is put in the indeterminate state with a dash.

Check the All checkbox

Click the All checkbox and your browser will look similar to the following screenshot.

When we checked the All checkbox, the two unchecked subcategory checkboxes became checked; Car and Jeep. The selected properties for All, Car, and Jeep became true in the debug panel, and the All checkbox was put in the checked state with a checkmark.

Uncheck the All checkbox

Click the All checkbox to uncheck it and your browser will look similar to the following screenshot.

By unchecking the All checkbox, the Car, Truck, and Jeep checkboxes were unchecked and the selected properties of All, and Car, Truck, and Jeep were set to false.

You can play around yourself with more checking and unchecking combinations to make sure everything is working correctly.

Removethe debug settings

We can remove the debug settings from the HTML at the this point.

  • Remove the open attribute from mat-sidenav element.
  • Set the pageSize attribute for the mat-paginator element back to 5.
  • Comment out the debug panel in the sidenav for now.

The following code is the complete vehicles component HTML at the end of this module.

<mat-sidenav-container>
  <mat-sidenav mode="side" #sidenav>
    <div style="margin-right: 10px;">
      <p><b>Search Panel</b></p>
      <hr />
      <p><b>Categories</b></p>
      <mat-checkbox color="primary"
                    [checked]="allCategoriesSelected"
                    [indeterminate]="someSearchCategoriesSelected()"
                    (change)="setAllCategoriesSelected($event.checked)">
        {{ categoryAll.name }}
      </mat-checkbox>
      <ul>
        <li *ngFor="let category of categoryAll.categories">
          <mat-checkbox color="accent"
                        [(ngModel)]="category.selected"
                        (ngModelChange)="updateAllCategoriesSelected()">
            {{category.name}}
          </mat-checkbox>
        </li>
      </ul>

      <!-- debug -->
      <!--
      <b>categoryAll:</b><br />
      {{ categoryAll.selected }}<br />
      <b>Categories:</b>
      <ul>
        <li *ngFor="let category of categoryAll.categories">
          {{category.name}}: {{ category.selected }}
        </li>
      </ul>
      -->
      <!-- debug -->
    </div>
  </mat-sidenav>
  
  <mat-sidenav-content>
    <p *ngIf="!(vehicles.data.length > 0)">
      <mat-spinner style="margin: 0 auto;"></mat-spinner>
    </p>

    <div>
      <button mat-icon-button
              color="primary"
              (click)="sidenav.toggle()">
        <mat-icon>
          search
        </mat-icon>
      </button>
    </div>
    <table mat-table [dataSource]="vehicles" matSort
           [ngClass]="{'hide-results' : vehicles.data.length <= 0}">

      <ng-container matColumnDef="vehicleType">
        <th mat-header-cell *matHeaderCellDef mat-sort-header>Category</th>
        <td mat-cell *matCellDef="let item">
          <b>{{ item.vehicleType }}</b>
        </td>
      </ng-container>

      <ng-container matColumnDef="id">
        <th mat-header-cell *matHeaderCellDef mat-sort-header>ID</th>
        <td mat-cell *matCellDef="let item">
          {{ item.id }}
        </td>
      </ng-container>

      <ng-container matColumnDef="status">
        <th mat-header-cell *matHeaderCellDef mat-sort-header>Status</th>
        <td mat-cell *matCellDef="let item">
          {{ item.status }}
        </td>
      </ng-container>

      <ng-container matColumnDef="year">
        <th mat-header-cell *matHeaderCellDef mat-sort-header>Year</th>
        <td mat-cell *matCellDef="let item">
          {{ item.year }}
        </td>
      </ng-container>

      <ng-container matColumnDef="make">
        <th mat-header-cell *matHeaderCellDef mat-sort-header>Make</th>
        <td mat-cell *matCellDef="let item">
          {{ item.make }}
        </td>
      </ng-container>

      <ng-container matColumnDef="model">
        <th mat-header-cell *matHeaderCellDef mat-sort-header>Model</th>
        <td mat-cell *matCellDef="let item">
          {{ item.model }}
        </td>
      </ng-container>

      <ng-container matColumnDef="color">
        <th mat-header-cell *matHeaderCellDef mat-sort-header>Color</th>
        <td mat-cell *matCellDef="let item">
          {{ item.color }}
        </td>
      </ng-container>

      <ng-container matColumnDef="price">
        <th mat-header-cell *matHeaderCellDef mat-sort-header>Price</th>
        <td mat-cell *matCellDef="let item">
          <b>{{ item.price | currency:"USD" }}</b>
        </td>
      </ng-container>

      <!-- No VIN on vehicles page.  We will show this on the details page -->
      <!-- Header Template -->
      <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
      <!-- Row Template -->
      <tr mat-row *matRowDef="let row; columns: columnsToDisplay"></tr>
    </table>

    <mat-paginator [pageSize]="5"
                   [pageSizeOptions]="[3, 5, 10]"
                   [ngClass]="{'hide-results' : vehicles.data.length <= 0}">
    </mat-paginator>

  </mat-sidenav-content>
</mat-sidenav-container>

What’s Next

Well, I think we covered a lot of ground in this module. We learned about and used the MatCheckbox component from the Angular Material library. And we wired up the checkboxes to manage an instance of the categoryAll interface we created and added to the data model.

We are not going to implement the vehicle results being filtered down by the category checkboxes UI yet. We need to get some background on how forms work in Angular first before we do that.

And in the upcoming modules that’s exactly what we’ll do when we build update and create components to allow users to edit and add vehicles. And then we will return to implementing some search features in our cool sidebar. But first we are going to make another house cleaning pitstop and add an image to our welcome page to make it look a little nicer. And then we are going to replace our mock data with a real database using Entity Framework Core migrations.

< Prev
Next >

Leave a ReplyCancel reply

Chapter 1: Static HTML – Designing the landing page.

  • Static HTML – Designing the landing page.
  • Let’s get started!
  • Mock your site with HTML
  • Make CSS easy with Bootstrap
  • Mock your content
  • Introducing JavaScript
  • JavaScript Code Improvements
  • Results Data
  • Images and the HTML Image Element.
  • Revisiting Reusability for CSS and JavaScript
  • Reuse for HTML: PART 1
  • Reuse for HTML: PART 2
  • Details Page – Using a Bootstrap Component
  • Creating Links
  • Chapter One Conclusion

Chapter 2: ASP.Net Core – Let’s talk Dynamic

  • Introduction to ASP.Net Core
  • What is .Net?
  • What is ASP.Net
  • Introduction to Entity Framework Core

Chapter 3: ASP.Net MVC Core – Models, Views, and Controllers [ASP.Net Core v9]

  • Introduction to ASP.Net Core MVC
  • Create the project: ASP.Net Core MVC
  • Explore the ASP.Net Core Empty Web Project Template
  • Configure the Application for MVC
  • Create a Controller: Home Controller
  • Create a View: Index View for the Home Controller
  • Install Bootstrap using Libman
  • Create the Layout template
  • Create the Model
  • Install EF Core & Create the Database
  • Seed the Database: Loading test data
  • DI (Dependency Injection): Display a List of Vehicles
  • Repository Pattern: The Vehicles Repo
  • Unit Test 1: Home Controller Can Use Vehicle Repository
  • Unit Test 2: Vehicle Repository Can Return List
  • Add the ImagePath Migration and Thumbnail images to results
  • Pagination: Create a Custom Tag Helper
  • Sorting
  • Category Filter
  • Partial View: Break out the vehicle results
  • View Component: Create dynamic category buttons
  • Create the Details page
  • Create the Create Page

Chapter 7: Using Server Side & Client Side technologies together. [ASP.Net Core v7 & Angular v15]

  • Intro to Full Stack Development
  • Fred’s Cars – Full Stack Development
  • Prepare the environment
  • Create the Visual Studio Solution
  • Add the ASP.Net Core Web API project
  • Add the Angular Project
  • Wire it up!
  • WeatherForecast: Understanding the basics
  • Vehicles API Controller: Mock Data
  • Vehicles Angular Component: Consuming Data
  • Routing and Navigation
  • Using a Component Library: Angular Material
  • Our first Angular Material Component: MatToolbar
  • Configuring for Saas: CSS with superpowers
  • Create the Header & Footer components
  • Displaying Results with MatTable
  • Loading: Using a Progress Spinner
  • MatTable: Client-Side Paging and Sorting
  • MatSidenav: Create a Search Sidebar
  • MatCheckbox: Category Search UI
  • Adding an image to the welcome page
  • Create the database with Entity Framework Core migrations
  • MatPaginator & PageEvent: Custom Server-Side Paging
  • Unit Testing: Custom Server-Side Paging
  • Repository Pattern: VehicleRepository
  • Unit Test: Paging in the Vehicles controller
  • Server-Side Sorting
  • Unit Tests: Sorting
  • Filter (Quick Search)
  • Unit Tests: Filter feature
  • Advanced Search: Categories
  • Unit Tests: Search by category
  • Progress Spinner: Final Fix

TOC

  • What were WebForms?
  • Enter MVC
    • Understanding MVC
    • Advantages of MVC
  • ASP.Net Core MVC – A total rewrite
  • ASP.Net Core 2 MVC – Here come Razor Pages
    • Understanding Razor Pages
  • ASP.Net Core 3 – Dropping the MVC reference
    • Understanding Blazor
  • Dropping the MVC reference
  • Hello .Net 5!
  • What’s Next? – Here comes .Net 6.

Recent Posts

  • Angular Commands Cheat Sheet
  • Installing Git for Windows
  • Installing Postman
  • Installing SQL Server 2022 Express
  • Installing Visual Studio 2022

Recent Comments

No comments to show.

Archives

  • November 2023
  • October 2023
  • June 2023
  • October 2021

Categories

  • Angular
  • ASP.Net
  • Environment Setup
  • See All
  • SQL Server
  • Visual Studio
  • Web API & Rest Services

WordPress Theme Editor

Copyright © 2025 Web Development School.

Powered by PressBook Blog WordPress theme