【AngularMaterial】月と日情報だけ取得するdatepicker

####やりたいこと：
・AngularMaterialのDatepickerを使って年情報はいらないからstringで"5月28日"とかで取得したい
・画像のように年情報は選べないようにしたい
![スクリーンショット 2020-05-29 14.11.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607742/bc9117d1-7f75-ebf6-95dd-e4c1a32a9f6b.png)

####やること:
・pickerのヘッダー部分のカスタム
・取得した情報をstringにフォーマット

####参考
[StackBlitz](https://stackblitz.com/edit/angular-hw54xf?file=src%2Fapp%2Fdatepicker-custom-header-example.ts)

####前準備
MomentDateAdapterとmomentのインストール

```
npm i moment
```

```
npm i @angular/material-moment-adapter
```

##カスタムするヘッダーのコンポーネントを作る

```
ng g c form-part/custom-header
```
フォルダ名やコンポーネント名はなんでもいいよ

```
@NgModule({
  declarations: [CustomHeaderComponent],
  imports: [...省略...],
  exports: [...省略...],
  entryComponents: [CustomHeaderComponent],
})
```
module.tsでentryComponentsに追加するのを忘れないように

###CustomHeaderComponent

```html
<div class="custom-datepicker-header">
  <span class="material-icons" (click)="previousClicked('month')">
    keyboard_arrow_left
  </span>
  <span class="custom-datepicker-label">{{ periodLabel }}</span>
  <span class="material-icons" (click)="nextClicked('month')">
    keyboard_arrow_right
  </span>
</div>
```
```scss
.custom-datepicker-header {
  display: flex;
  align-items: center;
  padding: 0.5em;
}

.custom-datepicker-label {
  flex: 1;
  height: 1em;
  font-weight: 500;
  text-align: center;
}
```
```typescript
import {
  ChangeDetectionStrategy,ChangeDetectorRef,Component,Inject,OnDestroy,
} from "@angular/core";
import { MatCalendar } from "@angular/material/datepicker";
import {
  DateAdapter,MAT_DATE_FORMATS,MatDateFormats,
} from "@angular/material/core";
import { Subject } from "rxjs";
import { takeUntil } from "rxjs/operators";

@Component({
  selector: "app-custom-header",
  templateUrl: "./custom-header.component.html",
  styleUrls: ["./custom-header.component.scss"],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomHeaderComponent implements OnDestroy {
  private _destroyed = new Subject<void>();

  constructor(
    private _calendar: MatCalendar<any>,
    private _dateAdapter: DateAdapter<any>,
    @Inject(MAT_DATE_FORMATS) private _dateFormats: MatDateFormats,
    cdr: ChangeDetectorRef
  ) {
    _calendar.stateChanges
      .pipe(takeUntil(this._destroyed))
      .subscribe(() => cdr.markForCheck());
    _dateAdapter.setLocale("ja"); //日本語にする
  }

  ngOnDestroy() {
    this._destroyed.next();
    this._destroyed.complete();
  }

  get periodLabel() { // 選択中の月を返す
    return this._dateAdapter
      .format(
        this._calendar.activeDate,
        this._dateFormats.display.monthYearLabel
      )
      .toLocaleUpperCase();
  }

  previousClicked(mode: any) { // 前の月を表示
    this._calendar.activeDate = this._dateAdapter.addCalendarMonths(
      this._calendar.activeDate,
      -1
    );
  }

  nextClicked(mode: any) { // 次の月を表示
    this._calendar.activeDate = this._dateAdapter.addCalendarMonths(
      this._calendar.activeDate,
      1
    );
  }
}
```

###カスタムしたヘッダーを設定する
datepickerを設置するコンポーネント

```html
<mat-form-field>
  <mat-label>Choose a date</mat-label>
  <input matInput [matDatepicker]="picker" />
  <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
  <mat-datepicker #picker [calendarHeaderComponent]="header"></mat-datepicker>
</mat-form-field>
```

```typescript
import { ChangeDetectionStrategy, Component } from "@angular/core";
import {
  DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE,
} from "@angular/material/core";
import {
  MomentDateAdapter,MAT_MOMENT_DATE_ADAPTER_OPTIONS,
} from "@angular/material-moment-adapter";
import { CustomHeaderComponent } from "../../form-part/custom-header/custom-header.component";

export const MY_FORMATS = {
  parse: {
    dateInput: "DD/MMM",
  },
  display: {
    dateInput: "MM月DD日",
    monthYearLabel: "MMM",
    dateA11yLabel: "LL",
    monthYearA11yLabel: "MMMM YYYY",
  },
};

@Component({
  selector: "app-date-picker",
  templateUrl: "./date-picker.component.html",
  styleUrls: ["./date-picker.component.scss"],
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [
    {
      provide: DateAdapter,
      useClass: MomentDateAdapter,
      deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS],
    },
    { provide: MAT_DATE_FORMATS, useValue: MY_FORMATS },
  ],
})
export class DatePickerComponent {
  header = CustomHeaderComponent;
  constructor() {}
}
```
[calendarHeaderComponent]で作ったカスタムコンポーネントを指定する

![スクリーンショット 2020-05-29 14.11.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607742/bc9117d1-7f75-ebf6-95dd-e4c1a32a9f6b.png)

これで月と日だけが選べるdatepickerの完成。

datepickerにformControlを設定してvalueを確認してみましょう

```typescript
export class DatePickerComponent implements OnInit {
  header = CustomHeaderComponent;
  date = new FormControl();

  constructor() {}
  ngOnInit() {}

  output() {
    console.log(this.date.value);
  }
}
```
```html
<mat-form-field>
  <mat-label>Choose a date</mat-label>
  <input
    matInput
    [matDatepicker]="picker"
    [formControl]="date"
    (dateChange)="output()"
  />
  <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
  <mat-datepicker #picker [calendarHeaderComponent]="header"></mat-datepicker>
</mat-form-field>
```
日付を選択したらコンソールにvalueを出力します
![スクリーンショット 2020-05-29 15.59.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607742/e1680645-8c85-29f0-a4fe-4707222aa040.png)

Momentで取得できているので　formatします

```typescript
  output() {
    let Moment = this.date.value as moment.Moment;
    console.log(Moment.format("MM月DD日"));
  }
```
![スクリーンショット 2020-05-29 16.07.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607742/87714991-e660-68ff-b0bd-1533437b5272.png)
目的の形になりました。

おそらくprovider:DateAdapterに指定するクラスを自作すれば
モーメントじゃなくて直接MM月DD日の形でvalue取得できると思いますが
それはまた別の機会に検討してみようと思います。