How do you create a nested, collapsing menu with Angular Material2?

I know this is an old question, but for others coming upon this page looking for the same thing, as I did, here's how I took care of it with the current version of Angular Material (6.4.6) and once you get the CSS styles done right, it works beautifully.

Please note that there still is no official support for this functionality, and you have to set it up yourself, which could be done a number of ways, but I chose to use only Angular Material components.

Here's example markup with some comments, using an object for your nav links:

<mat-sidenav-container>
  <mat-sidenav #sidenav
    class="sidenav"
    [mode]="mobileQuery.matches ? 'over' : 'side'"
    [opened]="mobileQuery.matches ? false : true">
    <mat-nav-list>
      <!-- wrap all the nav items in an accordion panel -->
      <mat-accordion [displayMode]="flat">
        <div *ngFor="let navItem of navList">

          <!-- use a simple div for an item that has no children,
            match up the styling to the expansion panel styles -->
          <div class="nav-head" *ngIf="navItem.pages.length === 0">
            <a class="nav-link"
              [routerLink]="navItem.link"
              routerLinkActive="selected"
              (click)="closeSidenav()">
              <mat-icon>{{navItem.icon}}</mat-icon>
              <span class="nav-link-text">{{navItem.heading}}</span>
            </a>
          </div>

          <!-- use expansion panel for heading item with sub page links -->
          <mat-expansion-panel *ngIf="navItem.pages.length > 0"
            class="mat-elevation-z0">
            <mat-expansion-panel-header class="nav-head" [expandedHeight]="'48px'">
              <mat-panel-title class="nav-link">
                <mat-icon>{{navItem.icon}}</mat-icon>
                <span class="nav-link-text">{{navItem.heading}}</span>
              </mat-panel-title>
            </mat-expansion-panel-header>
      
            <div class="nav-section">
              <!-- loop through all your sub pages inside the expansion panel content -->
              <div *ngFor="let navPage of navItem.pages"
                class="nav-item">
                <a class="nav-link"
                  [routerLink]="navPage.link"
                  routerLinkActive="selected"
                  (click)="closeSidenav()">{{navPage.title}}</a>
              </div>
            </div>
          </mat-expansion-panel>
        </div>
      </mat-accordion>
    </mat-nav-list>
  </mat-sidenav>
  <mat-sidenav-content>
    <div class="container-fluid">
      <router-outlet></router-outlet>
    </div>
  </mat-sidenav-content>
</mat-sidenav-container>

EDIT: To answer a couple of additional questions that were made, mobileQuery is coming from the Angular Material CDK which adds some helpers for detecting mobile breakpoints inside your components. See here: Angular Material CDK Layout

Also, my component file really doesn't do anything in this case other than pull the correct nav object to be displayed from a service, but here is an example of how I set up the objects (of course they could be whatever you need them to be)

[
  {
    heading: 'Dashboard',
    icon: 'dashboard',
    link: '/dashboard',
    pages: []
  },
  {
    heading: 'Main Heading',
    icon: 'settings',
    link: '/settings',
    pages: [
      {
        title: 'Subpage',
        link: '/settings/advanced',
        icon: ''
      }
    ]
  }
]

Unfortunately, as of now, the material design library doesn't provide any tool to do what you want.

Once it comes out, you may be able to use the tree component to achieve what you want. Otherwise, you should look to build one yourself. I have done so myself (in a proprietary codebase, unfortunately) and I'd be glad to help with specific questions. I used nested <md-list>s, <button md-icon-button>s and custom animations to do so.