大田区から発信するゆるゆる日記

主にITエンジニアに関する備忘録日記。たまに趣味も。何か不備があればコメント頂けると幸いです。Twitterアカウント https://twitter.com/ryuzan03

【HTML/Javascript】フロントエンドでCSVデータを出力する方法

※下記の内容に不備がありましたら、コメント頂けると幸いです。また、下記の内容をご使用頂ける場合は自己責任でお願いします。

【目次】

【20/6/26 追記】
この記事の内容だとExcelcsvを開くと文字化けする可能性があります。

この記事の内容+以下のサイトを参考にすると、Excelで開いても文字化けしないcsv(tav)ファイルを作ることができます(サイトのコメント欄も要チェックです)。まあExcel2016以降はUTF-8に対応されたみたいなので、この記事の内容でも問題ないかもですが...
javascript で作成したCSVファイルをエクセルで表示可能にする - Qiita

概要

Angular(フロントエンド)からCSVデータを出力したかったのですが、HTMLとJavascriptだけで簡単に出力ができたので、その備忘録を書きます。

今回のブログのコードはAngular(Typescript)で記述しますが、使用している技術はHTMLとJavascriptの技術になります。ですので、Javascriptを使用されている方も参考にできる記事になっていると思います。

CSVデータ出力方法

処理の流れ

  1. ユーザ(画面)がクリックイベントを発火する
  2. 多次元(2次元)配列でデータを作成
  3. 多次元(2次元)配列のデータをJSON形式に変換し、さらにCSV出力方法を追加
  4. HTMLでa要素を作成
  5. 4のa要素に3のJSON形式のデータとdownload属性を追加する
  6. HTMLドキュメントに5のa要素を追加する
  7. a要素でクリックイベントを発火させる
  8. a要素を破棄する

最終的にJSON形式に変換できればCSV出力はできるので、多次元(2次元)配列ではなくても、オブジェクトデータなどでもCSV出力は可能です。

多次元(2次元)配列を使った理由

2次元配列の構造は以下のような感じです。

var a = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
]


上記のデータのうち1つの要素がCSVの1行になるわけですが、上記データの構造と以下のCSVデータ構造(分かりやすいようにスプレッドシートの画像を載せています)を見比べてみるとどうですか?構造が似ていていませんか? spreadsheet
私は似ているなと思い、データ構造のイメージがしやすかったので、2次元配列を使うことにしました。

多次元(2次元)配列とは?

2つ以上のインデックスが組み合わさっている配列で、配列の中に配列があるイメージです。JavaScriptでは多次元配列という構文は用意されていませんが、多次元配列のように配列を組み合わせても使うことはできます。

詳しくはこちらをご覧ください。


画面とメソッドを作成

component.html

<button (click)="downloadCsv()">CSVダウンロード</button>

component.ts

export class TestComponent {
  downloadCsv() {
    // 以下で記述
  }
}



2次元配列データを作成し、JSON形式に変換

component.ts

downloadCsv() {
  const array: stirng[][] = [
    ['1', '2', '3'],
    ['4', '5', '6'],
    ['7', '8', '9'],
  ]
  // 本来であれば、foerEachやmapなどを使って2次元配列を作ることになるかと思います。その場合は、pushやconcat、new Arrayなどを使うことが多いと思います。
  const csvData: string = this.arrToCSV(array)
}

arrToCSV(array: string[][]): string {
  let csvData = 'data:text/csv;charset=utf-8,'; /// 最初にcsvDataに出力方法を追加しておく
  arr.forEach(a => {
    const row = a.join(',');
    csvData += row + '\r\n';
  });
  return csvData;
}



a要素を作成して、csvを出力

component.ts

downloadCsv() {
...
  const csvData: string = this.arrToCSV(array)

  const encodedUri = encodeURI(csvData); // csvDataをエンコード化する
  const ele = document.createElement('a'); // a要素を作成する

  ele.setAttribute('href', encodedUri);  // a要素に出力データを追加
  ele.setAttribute('download', 'test' + '.csv'); // a要素に出力情報を追加。「'test'」部分は変数を入れることも可能。
  ele.style.visibility = 'hidden';
  document.body.appendChild(ele);
  ele.click(); // HTMLドキュメントに追加したa要素を実行(clickイベント発火)
  document.body.removeChild(ele);
}



今後に向けて

知らないことが無限に出てくる。

参考

素晴らしい記事に感謝致します。
多次元配列 - 配列 - JavaScript入門
クライアント側でCSV生成してダウンロードさせる - ryotah’s blog
【JavaScript】配列データをCSVファイルとして保存できるようにする | あれは魔法だろうか?
Export JSON to CSV file in Angular - GeeksforGeeks

【Ionic/Angular】ion-navでネストがあるナビゲーション機能を実装

※下記の内容に不備がありましたら、コメント頂けると幸いです。また、下記の内容をご使用頂ける場合は自己責任でお願いします。

【目次】

概要

ion-navを使ってrouterを汚さずにページ遷移ができるようにしました。

ion-navのコンポーネントドキュメントだとJavascriptを使うので、私はコンポーネントを使う方法で実装してみました。何故Javascriptを使うのか理由が知りたい...
ion-nav - Ionic Framework 日本語ドキュメンテーション

また、Ionic5から実装されたion-nav-linkも使ってみました(代わりにion-nav-push・back・set-rootがなくなりましたね)
How to Upgrade Your App to Ionic 5 - Ionic AcademyIonic Academy

ちなみに、Angular Materialのmat-treeとion-navを使ってもできそうでしたが、ion-navが良い感じに使いこなせなくて私は途中で挫折しました。あと、ion-tree-listとかあったんですが、公式ではなかったので使うのやめました。ion-treeとかありそうなのにないんですね。

ion-navでネストがあるナビゲーション機能を実装

必要なコンポーネントとデータを作成

ターミナル

$ ionic g component parent
$ ionic g component children
$ ionic g service datas

data.ts

export interface Data {
  name: string;
  children?: Data[];
}


ここのデータ構造は重要です。

datas.ts

import { Data } from './data';

export const DATAS: Data[] = [
  {
    name: 'カテゴリー1',
    children: [
      {name: '子カテゴリー1'},
      {name: '子カテゴリー2'},
    ]
  },
  {
    name: 'カテゴリー2',
    children: [
      {name: '子カテゴリー1'},
      {name: '子カテゴリー2'},
    ]
  },
...
]

datas.service.ts

import { Injectable } from '@angular/core';
import { Data } from './data';
import { DATAS } from './datas';

@Injectable({
  providedIn: 'root'
})
export class DatasService {
  getDatas(): Data[] {
    return DATAS;
  }
}



parentコンポーネントとchildrenコンポーネントを修正

ここが今回最も重要な章です。

プログラミングしていくイメージは、ネストがあるデータやコンポーネントを親(page1・ParentComponent)から子(ChildrenCompnent)に順に渡すイメージです。

その時に使うのがion-navであったりion-nav-linkだったりします。親からデータを受け取る時にはNavParamsオブジェクトを使います。

children.component.ts

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

@Component({
  selector: 'ls-children',
  templateUrl: './children.component.html',
  styleUrls: ['./children.component.scss'],
})
export class ChildrenComponent implements OnInit {
  children: [{[key: string]: string}];

  constructor(private navParams: NavParams) { }

  ngOnInit() {
    this.children = this.navParams.data.children;
  }

}

children.component.html

<ion-header>
  <ion-toolbar>
    <ion-buttons slot="start">
      <ion-back-button></ion-back-button>
    </ion-buttons>
    <ion-title>
      子要素
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content  fullscreen>
  <ion-list>
    <ng-container *ngFor="let child of children"> 
      <ion-item button>
        <ion-icon name="arrow-forward" slot="end"></ion-icon>
        <ion-label>
          {{child.name}}
        </ion-label>
      </ion-item>
    </ng-container>
  </ion-list>
</ion-content>


parent.component.ts

import { Component, OnInit } from '@angular/core';
import { NavParams } from '@ionic/angular';
import { ChildrenComponent } from '../children/children.component';

@Component({
  selector: 'ls-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss'],
})
export class ParentComponent implements OnInit {
  datas: {[key: string]: any} = {};
  nextPage = ChildrenComponent;

  constructor(private navParams: NavParams) { }

  ngOnInit() {
    this.datas = this.navParams.data;
  }

}

children.component.html

<ion-header>
  <ion-toolbar>
    <ion-title>
      トップ
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content  fullscreen>
  <ion-list>
    <ng-container *ngFor="let data of datas"> 
      <ion-nav-link [component]="nextPage" [componentProps]="{'children': data.children}">
        <ion-item button>
          <ion-icon name="arrow-forward" slot="end"></ion-icon>
          <ion-label>
            {{data.name}}
          </ion-label>
        </ion-item>
      </ion-nav-link>
    </ng-container>
  </ion-list>
</ion-content>



pageにion-navを追加

page1.page.ts

import { Component, OnInit } from '@angular/core';
import { Dictionaries } from 'src/app/shared/models/dictionaries';
import { DatasService } from '../datas.service';
import { ParentComponent } from '../parent/parent.component';

@Component({
  selector: 'app-page1',
  templateUrl: 'page1.page.html',
  styleUrls: ['page1.page.scss']
})
export class Page1Page implements OnInit {
  datas: Datas[];
  navTop: any = ParentComponent;

  constructor(
    private datasService: DatasService,
  ) {}

  ngOnInit() {
    this.getDatas();
  }

  getDatas(): void {
    this.datas = this.datasService.getDatas();
  }

}

page1.page.html

<ion-content [fullscreen]="true">
  <ion-nav [root]="navTop" [rootParams]="datas"></ion-nav>
</ion-content>



応用ヒント

さらにネストが深い場合は、childrenにion-nav-linkを追加して、componentプロパティに自身(children)を反映させる変数を定義しましょう。

example

nextPage = ChildrenComponent


途中でネストを抜け出す場合はngIfを利用します。

example

<ng-container *ngIf="data.children">
...
</ng-container>


もしくは、ネストの深さが一定なら、それだけのコンポーネントを作るのも良さそうです。私はネストが1つだけだったので、parentコンポーネント・childrenコンポーネント・detailコンポーネントの3つで完結させました。


今後に向けて

Ionicは日本語の記事が少ないのでなかなか苦戦してます。。。

少しずつ慣れてはきてるので引き続き英語に負けずに頑張っていきたいと思います。


参考

素晴らしい記事に感謝致します。
ion-nav - Ionic Framework 日本語ドキュメンテーション
ionic-docs/index.html at master · ionic-team/ionic-docs · GitHub
ion-nav-link - Ionic Framework 日本語ドキュメンテーション
How to Upgrade Your App to Ionic 5 - Ionic AcademyIonic Academy

【Ionic/Angular】Tabsテンプレートで作ったIonicアプリにSideBarを追加する(別解編)

※下記の内容に不備がありましたら、コメント頂けると幸いです。また、下記の内容をご使用頂ける場合は自己責任でお願いします。

【目次】

概要

この記事は以前書いた記事【Ionic/Angular】Tabsテンプレートで作ったIonicアプリにSideBarを追加する - 大田区から発信するゆるゆる日記の別解となります。

以前書いた記事だと後々面倒なことになりそうだったので、色々と考えてたら下記の別解に辿り着きました。なかなか開発が前に進まないTT

Tabsテンプレートで作ったIonicアプリにSideBarを追加する(別解編)

前回と今回の比較

前回はtabs.pageをcomponent化し、各ページにそのcomponentを設置することで、SideBarメインのページに仕上げました。つまりionic startでsidebarを選んでアプリを作成し、そこにtabs.componentをねじ込んだイメージです。

今回はtabs.pageの中にSidebar.pageを作ります。Sidebar.pageの中で各ページを遷移させるイメージです。

別解に至った経緯

前回ではion-tab-buttonの性質上、属性tabを指定しているとページ遷移時にtabの属性値を現時点のページのURLに『追加』することになり、ルーティングがとてもややこしくなりました。ion-tab-buttonにはhref属性もあるのですが、ion-tabsのページ遷移の恩恵を受けることができない(ページを再読み込みしてしまう)ので却下としました。

ネットで諸先輩方のアプリを漁っているとtabs.pageの中にsidebar.pageを入れていたので、真似てみたら幸せになれました。

Ionicアプリを作成する。

$ ionic start project tabs --type=angular

MenuPageを追加する。
このMenuPageがサイドバーになります。

project $ ionic g page menu

app-routing.module.ts(menuを削除)

...
const routes: Routes = [
  {
    path: '',
    loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule)
  }
];
...

tabs-routing.module.ts

...
const routes: Routes = [
  {
    path: 'tabs',
    component: TabsPage,
    children: [
      {
        path: '',
        loadChildren: () => import('../menu/menu.module').then(m => m.MenuPageModule)
      },
      {
        path: '',
        redirectTo: '/tabs/tab1',
        pathMatch: 'full'
      }
    ]
  },
  {
    path: '',
    redirectTo: '/tabs/tab1',
    pathMatch: 'full'
  }
...

manu-routing.module.ts

...
const routes: Routes = [
  {
    path: '',
    component: MenuPage,
    children: [
      {
        path: 'tab1',
          loadChildren: () =>
          import('../tab1/tab1.module').then(m => m.Tab1PageModule),
      },
      {
        path: 'tab2',
          loadChildren: () =>
          import('../tab2/tab2.module').then(m => m.Tab2PageModule),
      },
      {
        path: 'tab3',
          loadChildren: () =>
          import('../tab3/tab3.module').then(m => m.Tab3PageModule)
      },
      {
        path: '',
        redirectTo: '/tabs/tab1',
        pathMatch: 'full'
      }
    ]
  },
  {
    path: '',
    redirectTo: '/tabs/tab1',
    pathMatch: 'full'
  }
];
...

menu.page.html

<ion-split-pane contentId="content">
  <ion-menu contentId="content">

    <ion-header>
      <ion-toolbar color="primary">
        <ion-title>MENU</ion-title>
      </ion-toolbar>
    </ion-header>

    <ion-content>
      <ion-list>
        <ion-menu-toggle auto-hide="false" *ngFor="let p of pages">
          <ion-item [routerLink]="p.url" routerDirection="root" [class.active-item]="selectedPath.startsWith(p.url)">
            <ion-label>
              {{p.title}}
            </ion-label>
          </ion-item>
        </ion-menu-toggle>
      </ion-list>
    </ion-content>
  </ion-menu>

  <ion-router-outlet id="content"></ion-router-outlet>
</ion-split-pane>

menu.page.ts

...
export class MenuPage {

  pages = [
    {
      title: 'tab1',
      url: '/tabs/tab1'
    },
    {
      title: 'tab2',
      url: '/tabs/tab2'
    },
    {
      title: 'tab3',
      url: '/tabs/tab3'
    },
  ];

  selectedPath = '';

  constructor(private router: Router) {
    this.router.events.subscribe((event: RouterEvent) => {
      if (event && event.url) {
        this.selectedPath = event.url;
      }
    });
   }
}


タブの表示/非表示を実装する

TabsPageの表示/非表示を実装します。

tabs.component.scss

@media screen and (min-width: 992px) {
  ion-tab-bar {
    display: none;
  }
}


今後に向けて

ion-tab-buttonの属性について理解していなかったため、ややこしい実装をしてしまいました。
参考書とか見ずに新しい機能を実装する時は、公式リファレンスを見ておいた方が良さそうですね。個人開発だとなかなか難しそうですが。。。

参考資料

素晴らしい記事に感謝致します。
ion-tab-button - Ionic Documentation

【Ionic/Angular】Tabsテンプレートで作ったIonicアプリにSideBarを追加する(エラー対応編)

※下記の内容に不備がありましたら、コメント頂けると幸いです。また、下記の内容をご使用頂ける場合は自己責任でお願いします。

【目次】

概要

前回のブログ【Ionic/Angular】Tabsテンプレートで作ったIonicアプリにSideBarを追加する - 大田区から発信するゆるゆる日記でエラーが発生しました。

本来であれば前回の記事を修正するのがいいと思うのですが、前回の内容が多かったので新しく記事を書くことにしました。

エラー対応

エラー内容

各ページに設置した要素に何かしらのアクション(クリックなど)をしても反応しない。

原因

これはIonicの構造的な問題です。
HTMLの構造で考えるとすぐに分かりそうなことですが、「ion-content」と「ls-tabs」が干渉しあって「ls-tabs」がオーバーラッピング(overlapping)しています。

前回ブログのtab1/tab2/tab3.page.html

<ion-header [translucent]="true">
  <ion-toolbar>
    <ion-title>その他</ion-title>
  </ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true">
  <ion-button (click)="test()"></ion-button>
</ion-content>

<ls-tabs></ls-tabs>


解決

こちらの公式ガイドStructure - Ionic Documentationを見て解決しました。
以下のようにtab1/tab2/tab3.page.htmlとscssを変更します。

tab1/tab2/tab3.page.heml

...
</ion-content>

<ion-footer>
  <ion-toolbar>
    <ls-tabs></ls-tabs>
  </ion-toolbar>
</ion-footer>
...

tab1/tab2/tab3.page.scss

...
@media screen and (min-width: 992px) {
  ion-footer {
    display: none;
  }
}
...


今後に向けて

「分かった!」と思ってしまうと一気に開発を進めてしまうので、少しずつ開発を進めるようにしたいです。

それ以前にテスト書いとけって話かもしれませんが...

参考資料

素晴らしい記事に感謝致します。
Structure - Ionic Documentation
angular - ion-button Click not firing up function in ionic 4 - Stack Overflow

【Ionic/Angular】Tabsテンプレートで作ったIonicアプリにSideBarを追加する

※下記の内容に不備がありましたら、コメント頂けると幸いです。また、下記の内容をご使用頂ける場合は自己責任でお願いします。

【目次】

【2020/5/7 追記】
今回の記事の別解を書きました。別解の方がスマートなので、個人的には別解で実装することをオススメします。
【Ionic/Angular】Tabsテンプレートで作ったIonicアプリにSideBarを追加する(別解編) - 大田区から発信するゆるゆる日記

【2020/4/28 追記】
下記の内容では遷移後のページでアクション(イベント)を起こしても反応しないことが分かりました。この記事の内容が多いため、エラー解決方法については別の記事に書かせていただきます。詳しくはこちら【Ionic/Angular】Tabsテンプレートで作ったIonicアプリにSideBarを追加する(エラー対応編) - 大田区から発信するゆるゆる日記をご確認ください。

概要

Tabsテンプレートで作ったIonicアプリにSidebarを追加してみました。意外に躓いたので備忘録にします。

あと恐らくこれはベストプラクティスではないと思います。「こうした方がいいよ」とかあれば、コメントいただければとても嬉しいです。

完成イメージと参考動画

完成イメージはこちらです。
デスクトップではslidebar、スマホではtabsが表示されるようにします。
Ionic Frameworkを用いたデスクトップレイアウトを考える - Qiita

slidebarを追加する際に参考にした動画です。
How to Combine Ionic 4 Tabs and Side Menu Navigation - YouTube


Tabsテンプレートで作ったIonicアプリにSideBarを追加する

ポイント

ポイントはMenuPageのion-split-paneにcontentIdを追加することとmenu-routingのややこしいルーティングです。

contentIdの追加は参考にした動画では追加されていないので忘れがちです。

Ionicアプリを作成する。

$ ionic start project tabs --type=angular

MenuPageを追加する。
このMenuPageがサイドバーになります。

project $ ionic g page menu

app-routing.module.ts

...
const routes: Routes = [
  {
    path: '',
    loadChildren: () => import('./menu/menu.module').then( m => m.MenuPageModule)
  }
];
...

menu.page.html

<ion-split-pane contentId="content">
  <ion-menu contentId="content">

    <ion-header>
      <ion-toolbar color="primary">
        <ion-title>MENU</ion-title>
      </ion-toolbar>
    </ion-header>

    <ion-content>
      <ion-list>
        <ion-menu-toggle auto-hide="false" *ngFor="let p of pages">
          <ion-item [routerLink]="p.url" routerDirection="root" [class.active-item]="selectedPath.startsWith(p.url)">
            <ion-label>
              {{p.title}}
            </ion-label>
          </ion-item>
        </ion-menu-toggle>
      </ion-list>
    </ion-content>
  </ion-menu>

  <ion-router-outlet id="content"></ion-router-outlet>
</ion-split-pane>

menu.page.ts

...
export class MenuPage {

  pages = [
    {
      title: 'tab1',
      url: '/menu/tab1'
    },
    {
      title: 'tab2',
      url: '/menu/tab2'
    },
    {
      title: 'tab3',
      url: '/menu/tab3'
    },
  ];

  selectedPath = '';

  constructor(private router: Router) {
    this.router.events.subscribe((event: RouterEvent) => {
      if (event && event.url) {
        this.selectedPath = event.url;
      }
    });
   }
}

menu-routing.module.ts

...
const routes: Routes = [
  {
    path: 'menu',
    component: MenuPage,
    children: [
      {
        path: 'tab1',
        children: [
          {
            path: '',
            loadChildren: () =>
            import('../tab1/tab1.module').then(m => m.Tab1PageModule),
          },
          {
            path: 'tab1',
            redirectTo: '',
            pathMatch: 'full'
          },
        ]
      },
      {
        path: 'tab2',
          children: [
            {
              path: '',
              loadChildren: () =>
              import('../tab2/tab2.module').then(m => m.Tab2PageModule),
            },
            {
              path: 'tab2',
              redirectTo: '',
              pathMatch: 'full'
            }
          ]
      },
      {
        path: 'tab3',
        children: [
          {
            path: '',
            loadChildren: () =>
              import('../tab3/tab3.module').then(m => m.Tab3PageModule)
          },
          {
            path: 'tab3',
            redirectTo: '',
            pathMatch: 'full'
          }
        ]
      },
      {
        path: '',
        redirectTo: '/menu/tab1',
        pathMatch: 'full'
      }
    ]
  },
...


タブの表示/非表示を実装する

TabsPageを利用してタブの表示/非表示を実装します。
今回はTabsPageをコンポーネント化してSharedModuleに登録し、各tabに追加していきます。

SharedModuleを作成する

project $ ionic g module shared

tabs.component.ts

...
@Component({
  selector: 'ls-tabs',
  templateUrl: 'tabs.component.html',
  styleUrls: ['tabs.component.scss']
})
export class TabsComponent {
  constructor() {}
}
...

tabs.component.scss

@media screen and (min-width: 992px) {
  ion-tab-bar {
    display: none;
  }
}

shared.module.ts

...
@NgModule({
  imports: [
    CommonModule,
    IonicModule
  ],
  declarations: [TabsComponent],
  exports: [TabsComponent],
})
...

tab1/tab2/tab3.page.html

...
</ion-content>
<ls-tabs></ls-tabs>

tab1/tab2/tab3.module.ts

imports: [
  ...
  SharedModule,
  ...
],


タブのルーティングを紐付ける

menu-routing.module.ts

...
      {
        path: 'tab3',
        children: [
          {
            path: '',
            loadChildren: () =>
              import('../tab3/tab3.module').then(m => m.Tab3PageModule)
          },
          {
            path: 'tab3',
            redirectTo: '',
            pathMatch: 'full'
          }
        ]
      },
      {
        path: 'tab2/tab1',
        redirectTo: 'tab1',
        pathMatch: 'full'
      },
      {
        path: 'tab3/tab1',
        redirectTo: 'tab1',
        pathMatch: 'full'
      },
      {
        path: 'tab1/tab2',
        redirectTo: 'tab2',
        pathMatch: 'full'
      },
      {
        path: 'tab3/tab2',
        redirectTo: 'tab2',
        pathMatch: 'full'
      },
      {
        path: 'tab1/tab3',
        redirectTo: 'tab3',
        pathMatch: 'full'
      },
      {
        path: 'tab2/tab3',
        redirectTo: 'tab3',
        pathMatch: 'full'
      },
      {
        path: '',
        redirectTo: '/menu/tab1',
        pathMatch: 'full'
      }
    ]
  },
  {
    path: '',
    redirectTo: '/menu/tab1',
    pathMatch: 'full'
  }
];
...


今後に向けて

今回はTabsテンプレートを尊重するあまりルーティングがややこしくなってしまいました。
各タブにURLを割り当てていたらもっと簡単になってたのかな...

もっとスマートな方法を知っている方がいましたらコメントお願いします!

参考資料

素晴らしい記事に感謝致します。
ion-split-pane - Ionic Framework 日本語ドキュメンテーション
Angular Lazy LoadingでつまずいちゃうNgModuleのコンポーネント登録 - Qiita
Ionic Frameworkを用いたデスクトップレイアウトを考える - Qiita
How to Combine Ionic 4 Tabs and Side Menu Navigation - YouTube

【Firebase/Angular】AngularFireAuthのauthプロパティ削除について

※下記の内容に不備がありましたら、コメント頂けると幸いです。また、下記の内容をご使用頂ける場合は自己責任でお願いします。

【目次】

概要

AngularFire6.0からAngularFireAuthのauthプロパティが削除されましたので、その内容について備忘録を書いていきます。


AngularFire authプロパティの変更

AngularFire6.0での変更点

今回はAngularFireAuthの変更にフォーカスを当てて解説と使い方を見ていきます。

  • AngularFireAuth has dropped the auth property and instead Promise Proxies the underlying Firebase auth.Auth instance; allowing your development experience to more closely mirror the JS SDK. Similar changes have been made to AngularFireFunctions, AngularFireMessaging, and AngularFirePerformance.

【和訳】
AngularFireAuthはauthプロパティを削除し、代わりにFirebaseのauth.Authインスタンスをプロキシするようになりました。同様の変更がAngularFireFunctions、AngularFireMessaging、AngularFirePerformanceにも行われました。

変更点の全文はこちらから。

要は「authプロパティは削除したから、これからはFirebaseのauth.Authインスタンスを代わりに使ってね」ということですね。


使い方

今回は現在ログインしているユーザーのuidを取得する方法を例に使い方を見ていこうと思います。
Firebase のユーザーを管理する
Angularで使うFirebaseの認証系API一覧 - Qiita

Firebase

component.ts

import * as firebase from 'firebase';
...
getUserId(): string {
  return firebase.auth().currentUser.uid;
}


AngularFireAuth(おまけ)
import { AngularFireAuth } from '@angular/fire/auth';
...

constructor(
  public afAuth: AngularFireAuth
) {}
...

getUserId(): string {
  return this.afAuth.auth.currentUser.uid;
}



参考資料

素晴らしい記事に感謝致します。
angularfire/version-6-upgrade.md at master · angular/angularfire · GitHub
Firebase のユーザーを管理する
Angularで使うFirebaseの認証系API一覧 - Qiita

【Ionic/Angular】iOSアプリ開発におけるLocalNotificationsの挙動

※下記の内容に不備がありましたら、コメント頂けると幸いです。また、下記の内容をご使用頂ける場合は自己責任でお願いします。

【目次】

概要

本格的にIonicでアプリ開発を始めました。
参考書は「Ionicで作るモバイルアプリ制作入門[Angular版]」です。
初心者の方でも本の通りに開発を進めればちゃんとアプリが作れる内容になっていると思います。

今回はLocalNotificationsの実装で詰まったところがあったので備忘録として書いていきます。

iOSアプリ開発におけるLocalNotificationsの挙動

問題発生

参考書に則ってLocalNotificationsを実装していたのですが、iOSで挙動を確認すると動作はしているけど通知が表示されない。Androidでは通知は来るしWebでも動作は確認できる。

確認環境

・Ionic 5.0.0
・Angular 8.3.23
Xcode
・iPhone11ProMax

対策①

IonicのドキュメントからLocalNotifications(capacitor)をインストールします。
Local Notifications - Ionic Framework 日本語ドキュメンテーション

app.module.tsでLocalNotificationsをインポートする必要があります。

app.module.ts

import { LocalNotifications } from '@ionic-native/local-notifications/ngx';
...
providers: [
  LocalNotifications
]
...

これでiOSで動くようになりましたが、Androidの方で挙動がおかしくなりました。

対策②

Xcodeの設定を変更します。
Push Notifications - Capacitor

Signing&CapabilitiesにPush Notificationsを追加します。
Signing&Capabilities画面の左上にある「+Capability」を押します。 Xcode ウィンドウが開くので「Push Notifications」を検索してダブルクリックします。 LocalNotifications これでiOSでも通知が来るようになります。

結論

「Ionicで作るモバイルアプリ制作入門[Angular版]」で開発を進めるのであればXcodeの設定を変えるのがいいと思います。

参考

素晴らしい記事に感謝致します。
Push Notifications - Capacitor
Local Notifications - Ionic Framework 日本語ドキュメンテーション