Angular から Electron 経由でローカルファイル呼び出し

[前回](https://qiita.com/koronpo/items/8dca72ed1fe74143942e) Angular での Electron イベント呼び出し出来たので、次はローカルファイル呼び出し。

# ファイル呼出処理の追加

## localFileModule.js の追加
main.js が最終的にごちゃついても嫌なので localFileModule.js を作成。

```js
const {shell} = require('electron');

// ファイル呼び出しボタンが押されたとき
exports.openFile = function () {
  shell.openItem('[your file path]');
}
```

として main.js は

```js
const { app, BrowserWindow, ipcMain } = require('electron');
const lfm = require('./localFileModule.js');
let win;

function createWindow() {

  // ウインドウの作成
  win = new BrowserWindow({
    width: 800
    , height: 400
    , webPreferences: {
      nodeIntegration: true
    }
  })

  // ウインドウに表示する内容
  win.loadFile('dist/sample1/index.html');

  // デバッグ画面表示
  win.webContents.openDevTools();

  // このウインドウが閉じられたときの処理
  win.on('closed', () => {
    win = null;
  })
}

// アプリが初期化されたとき（起動されたとき）
app.on('ready', () => {
  createWindow();
})

// 全ウインドウが閉じられたとき
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
})

// アクティブになったとき（MacだとDockがクリックされたとき）
app.on('activate', () => {
  if (win === null) {
    createWindow();
  }
})

// ファイル呼び出し
ipcMain.on('callFile', (event, arg) => {
  lfm.openFile();
})
```

にしておく。

## Angular からボタンクリックでファイル呼び出しを行う

```/sample1/src/app/app.component.ts``` を以下に。

```ts
import { Component } from '@angular/core';
import { IpcRenderer } from 'electron';

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

  constructor() {
    if ((window as any).require) {
      try {
        this.ipc = (window as any).require('electron').ipcRenderer;
      } catch (e) {
        throw e;
      }
    } else {
      console.warn('App not running inside Electron!');
    }
  }

  // ボタンクリックで ipc の指定イベント呼び出し
  public clickcallFileBtn() {
    this.ipc.send('callFile');
  }
}
```

にして

```/sample1/src/app/app.component.html``` を

```html
<button type="button" name="button" (click)="clickcallFileBtn()">
  ファイル呼び出し
</button>
```

## 動作確認

```
npm run start:electron
```

でビルド、ボタンクリックで指定ファイルの呼び出しが可能に。

![file_test1_720.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/12a02a78-1269-38aa-8d3c-9bce1cd7c4e4.gif)


# ファイルが存在しない場合

ファイルが存在しない場合、画面上にはエラーが出ないのでその対応として、ファイルの存在チェック処理を追加。ファイルが存在しない場合はダイアログを表示するようにする。localFileModule.js を以下のように編集。

```js
const {shell} = require('electron');
const fs = require('fs');
const fsPromises = fs.promises;
const { dialog } = require('electron');

//openFileボタンが押されたとき（ファイル名取得まで）
exports.openFile = function () {
  const filePath = '[your file path]';

  fsPromises.access(filePath, fs.constants.R_OK | fs.constants.W_OK)
    .then(() => shell.openItem(filePath))
    .catch(() => showMessageBox());
}

// ダイアログメッセージ表示
function showMessageBox() {
  var options = {
    type: 'info',
    buttons: ['OK'],
    title: 'File not found',
    message: 'File not found',
    detail: 'ファイルが見つかりませんでした'
  };

  dialog.showMessageBox(null, options);
}
```

![file_test2_720.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/322617/8f2d930a-fa17-7a48-5321-68ac55eab9b6.gif)


# 感想
ローカルファイル呼び出しが普通に出来てなんというかセキュリティ的にどうなのかという疑問はあるものの、ブラウザで越えられない壁をいとも容易く越えてヤベェ。