質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.10%

Angular Materialのsidenav表示切替ボタンをHeaderに入れたい

受付中

回答 0

投稿

  • 評価
  • クリップ 0
  • VIEW 589

dev3310

score 24

Angularの勉強中です。

ハンバーガーメニューのように、ボタンで表示できるサイドメニューが作りたいです。

色々調べた結果Angular Materialのsidenavを使おうと思っています。
今回はsidenavをコンポーネントとして実装し、ディレクトリ構造は以下のようにしています。
(ゆくゆくはサイドメニューの中をDBから取得した情報をもとに表示したい為、sidenavというserviceを設けていますが現在は使用していません)

app
├ component
│ ├common
│ │ ├ header
│ │ │ ├header.component.html
│ │ │ ├header.component.scss
│ │ │ ├header.component.spec.ts
│ │ │ └header.component.ts
│ │ ├ sidenav
│ │ │ ├sidenav.component.html
│ │ │ ├sidenav.component.scss
│ │ │ ├sidenav.component.spec.ts
│ │ │ └sidenav.component.ts
├ service
│ ├common
│ │ ├ sidenav
│ │ │ ├sidenav.service.spec.ts
│ │ │ └sidenav.service.ts
├ utils
│ ├material
│ │ └material.module.ts
├ app-routing.module.ts
├ app.component.html
├ app.component.scss
├ app.component.spec.ts
├ app.component.ts
├ app.module.ts
└ etc...


現在のソースコードは以下の通りです。

【header.component.html】

header
<p><button mat-button (click)="sidenav.toggle()">sidenav.toggle()</button></p>

【header.component.ts】

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss']
})
export class HeaderComponent implements OnInit {
  constructor() { }
  ngOnInit() {
  }
}

【sidenav.component.html】

<mat-nav-list>
・メニュー1<br>
・メニュー2
</mat-nav-list>

【sidenav.component.ts】

import { Component, OnInit, Output, EventEmitter } from '@angular/core';
import { SidenavService } from 'src/app/service/common/sidenav/sidenav.service';
// import { AvailableMenuListDto } from 'src/app/entity/dto/available-menu-list-dto';

@Component({
  selector: 'app-sidenav',
  templateUrl: './sidenav.component.html',
  styleUrls: ['./sidenav.component.scss']
})
export class SidenavComponent implements OnInit {
  @Output() sidenavClose = new EventEmitter();
  constructor(
    private sidenavService: SidenavService,
  ) { }
  ngOnInit() {
    // メニューを取得する。
    // this.getAvailableMenu();
  }
  /**
   * メニュー選択後に親コンポーネントに対してクローズイベントを発生する。
   */
  public onSidenavClose() {
    this.sidenavClose.emit();
  }
}

【material.module.ts】

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
// Angular Materialで使用するモジュールをここに追加
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatMenuModule } from '@angular/material/menu';
import { MatListModule } from '@angular/material/list';
import { MatIconModule } from '@angular/material/icon';

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    MatSidenavModule,
    MatToolbarModule,
    MatMenuModule,
    MatListModule,
    MatIconModule,
  ],
  exports: [
    MatSidenavModule,
    MatToolbarModule,
    MatMenuModule,
    MatListModule,
    MatIconModule,
  ]
})
export class MaterialModule { }

【app-routing.module.ts】

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

【app.component.html】

<mat-sidenav-container>
    <!-- sidenav -->
    <mat-sidenav #sidenav mode="side">
      <app-sidenav (sidenavClose)="sidenav.close()"></app-sidenav>
    </mat-sidenav>
    <!-- main content -->
    <mat-sidenav-content>
        <app-header></app-header>
    </mat-sidenav-content>
  </mat-sidenav-container>

【app.component.ts】

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'AngularTest';
}

【app.module.ts】

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HeaderComponent } from './component/common/header/header.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MaterialModule } from 'src/app/utils/material/material.module';
import { SidenavComponent } from './component/common/sidenav/sidenav.component';


@NgModule({
  declarations: [
    AppComponent,
    HeaderComponent,
    SidenavComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    MaterialModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

現在はheaderの中に
<p><button mat-button (click)="sidenav.toggle()">sidenav.toggle()</button></p>
を入れており、これをクリックすると
Cannot read property 'toggle' of undefined
というエラーになってしまいます。

ただ、このボタンを【app.component.html】にそのまま書くとうまく動きます。
ボタンをHeaderに入れても動くようにするにはどうすればよいのでしょうか。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる