VoltMX V9.5の新機能 Navigation Managerを使ってみた

# 目次
1. はじめに
1. 概要
1. 実装方法
1. 実装結果
1. 最後に



# はじめに
V9.5から新たに追加されたNavigation Managerの機能について
実際に使用しながら実装方法をご紹介します！

https://opensource.hcltechsw.com/volt-mx-docs/95/docs/documentation/VMX_release_notes.html#v9-servicepack-5-fixpack-4

# 概要
Navigation Managerという機能は、
フォーム間および複数のMicro Apps間の画面遷移ロジックを1つの場所で定義することができます。

Navigation Managerが導入される以前は、
画面遷移は1対1（常に同じフォームへ）または1対多（条件付きフォームナビゲーション）において、
各画面で遷移先のフォームを指定する必要がありました。
この方法の場合、各画面ごとのControllerに手を加えなければならないため、
開発・保守に時間がかかるのが課題でした。

V9.5以降、
フォーム間および複数のMicro Apps間の画面遷移フローを
Navigation Managerという1つの場所で管理できるため、
アプリケーションフローの可読性とアプリケーションコードの保守性が向上しました。

# 実装方法
では早速使用方法をご紹介していきます！

## 完成イメージ
実装の前に、今回の画面遷移イメージは以下の通りです。

![スクリーンショット 0005-03-02 17.17.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/41851df0-276d-b308-543d-6a891b38eb39.png)

frmMainからfrmHomeへは1対1で画面遷移を行い、
frmHomeからは、
ログインボタンが押されたら、frmLogin
マイページボタンが押されたら、frmMypageに遷移するような簡単な画面遷移を作っていきたいと思います。

## 1.画面作成
早速、必要な画面を作成していきましょう！

|frmMain|frmHome|frmLogin|frmMypage|
|---|---|---|---|
|![スクリーンショット 0005-03-02 14.54.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/066d3f92-06f2-24c7-ce00-1d35b5b2d7e6.png)|![スクリーンショット 0005-03-02 14.54.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/45df3320-5812-9927-ff3b-11494b4984fe.png)|![スクリーンショット 0005-03-02 14.54.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/45f24900-157f-2eb4-ced9-87e6bf7c8c75.png)|![スクリーンショット 0005-03-02 14.54.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/b7ac5626-3436-5d8f-a57d-07bb89ce51e2.png)|

frmMainには、frmHomeに遷移するためのボタンを1つ配置、
frmHomeには、2つボタンを配置しfrmLoginとfrmMypageに遷移できるように画面を作成しました。

では早速、Navigation Managerを使って画面遷移を作っていきましょう！

## 2.画面遷移ロジック作成

Navigation Managerは、Controllerの下に配置されており、
画面間のナビゲーションは、
`NavigationController.js`と`NavigationModel.json`で定義することができます。
![スクリーンショット 0005-02-24 13.47.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/c4c6ff4e-b9d3-856f-bd56-28082e55d91f.png)


### 2-1.NavigationModelで遷移先を定義
NavigationModelでは、各画面の遷移先を定義します。

今回、[完成イメージ](#完成イメージ)に沿って以下のようにロジックを作成しました。

```NavigationModel.json
{
  "Forms": {
    //1対1
    "frmMain": {
      "preConditionConfig": [],
      "destinationConfig": {
        "friendlyName": "frmHome"
      }
    },
    //1対多
    "frmHome": {
      "preConditionConfig": [],
      "destinationConfig": {
        "callback": "frmHomeNavigationHandler",
        "targetForms": [
          {
            "friendlyName": "frmLogin"
          },
          {
            "friendlyName": "frmMypage"
          }
        ]
      }
    }
  }}
```
各値を説明していきます。

`preConditionConfig`：フォームの前提条件を定義します。
例えば、トークンを次の画面に渡したい場合は`"preConditionConfig" : [ "token" ]`のように指定することが可能です。
画面遷移中に遷移先に前提条件が宣言されている場合、遷移元のフォームは前提条件を定義する必要があります。

`destinationConfig`：遷移先の情報を定義します。
各パラメーターの指定はそれぞれ次のように指定します。

|パラメータ|必須/任意|概要|
|--|--|--|
|appName|必須（※）|アプリ間で画面遷移する場合、遷移先のアプリの名前を指定<br> ※アプリ内ナビゲーションの場合は任意です。|
|friendlyName|必須|遷移先のフォーム名を指定|
|callback|必須（※）|遷移時に呼び出すコールバック関数を指定。関数はNavigationControllerで定義します。※1対多の画面遷移の場合必須。|
|targetForms|必須（※）|遷移先のフォームを格納するオブジェクト。関数内で指定するフォームは、targetFormsのリストに定義しておく必要があります。※1対多の画面遷移の場合必須|


```NavigationModel（frmMain部分）.json
    "frmMain": {
      "preConditionConfig": [],
      "destinationConfig": {
        "friendlyName": "frmHome"
      }
    }
```
まず、frmMainの画面遷移データを作成していきます。
`"対象フォームのID名"{}`とすることで、
そのフォームの画面遷移先等を定義することができます。

今回frmMainからの画面遷移先はfrmHomeのみなので、
destinationConfig（遷移先情報）にfrmHomeを指定しています。
同じアプリ内で1対1で画面遷移する場合は、これだけの情報でOKです。

```NavigationModel（frmHome部分）.json
    "frmHome": {
      "preConditionConfig": [],
      "destinationConfig": {
        "callback": "frmHomeNavigationHandler",
        "targetForms": [
          {
            "friendlyName": "frmLogin"
          },
          {
            "friendlyName": "frmMypage"
          }
        ]
      }
    }
```
次に、frmHome画面では、frmLoginまたはfrmMypageに画面遷移するため、
destinationConfigの中にcallbackとtargetFormsを指定する必要があります。

どの画面に遷移させるかのコールバックを`frmHomeNavigationHandler`で制御し、
targetFormsには、遷移先の2つのフォーム名を指定します。

:::note
1対1の画面遷移と1対多の画面ロジックフローの違い

**1対1の画面遷移**
1対1の画面遷移の場合、
画面遷移ロジックは`NavigationModel.json`で完結するため
`NavigationController`を特に操作する必要はありません。
![スクリーンショット 0005-03-02 17.32.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/e42e8807-dde9-4b8c-1798-8d3b5b40ad60.png)

**1対多の画面遷移**

1対多の画面遷移の場合、
条件分けが必要なため`NavigationController`が必須となります。
NavigationModelで対象フォームと関数を定義し、
Controller上で関数を使って画面フローを制御するようなイメージです。
![スクリーンショット 0005-03-02 16.24.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/f572de48-b572-1848-6ae1-5ac22b1c2bdb.png)
:::


これでNavigationModelの作成は完了です。

次に、frmHomeから画面遷移を行う際に呼び出すcallback関数を
NavigationControllerに定義していきます！

### 2-2.NavigationControllerで条件付きの画面遷移ロジック作成
NavigationControllerは、
1つの画面から複数の画面に遷移する場合、画面遷移の条件ロジックを定義する場所になります。

こちらは通常のControllerと同じようにロジックを作成していけばOKです。
```NavigationController.js
define({
  frmHomeNavigationHandler : function(modelConfig){
    if(!modelConfig){
      return;
    }
    
    let destinationForm = null;
    
    if(modelConfig.navigateTofrmLogin === true){
      destinationForm = {
        "friendlyName": "frmLogin"
      };
    } else if(modelConfig.navigateTofrmMypage === true){
      destinationForm = {
        "friendlyName": "frmMypage"
      };
    }
    return destinationForm;
  }
});
```
フォームから渡されるconfig情報によって、画面の出し分けを行っています。
`modelConfig.navigateTofrmLogin`がある場合は、ログイン画面へ
`modelConfig.navigateTofrmMypage`がある場合は、マイページ画面へというロジックになっています。

各フォームからどのようにしてconfig情報を渡すかについてはこの後ご説明します。
NavigationModelとNavigationControllerが完成したので、
最後にフォーム側のアクション設定を行っていきましょう！



## 3.アクション作成

あともう少しで完成です！
最後に、画面遷移元のfrmMainとfrmHomeにアクションを定義していきましょう！

まずはメイン画面のロジックです。
```frmMainController.js
define({ 
  navigateTofrmHome : function(){
    var navConfig = { "context" : this};
    var navManager = voltmx.mvc.getNavigationManager();
    navManager.navigate(navConfig);
  }
 });
```
対象画面のControllerで、
`voltmx.mvc.getNavigationManager()`APIを使うことで、
NavigationModelが呼び出されます。

また`navManager.navigate`で`navConfig`のパラメーターを入れることで、
`NavigationController.js`に値が渡され、[2-2の手順](#NavigationControllerで条件付きの画面遷移ロジック作成)で作成した関数が実行されます。

メイン画面のボタンにアクションを追加します。
![スクリーンショット 0005-03-02 16.40.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/bd5a9164-4e5d-5d1f-a20f-7121b4d6f3c5.png)

アクションエディタで`frmMainController`で作成した、
`navigateTofrmHome`関数を選択しましょう。
![スクリーンショット 0005-03-02 16.41.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/7ad0dc9f-cf1d-30e0-52dc-dc6ff2e282aa.png)

これでfrmMainの画面遷移ロジックは完成です。

次は、frmHomeのロジックを作成していきます。

```frmHomeController.js
define({ 
  navigateTofrmLogin : function(){
    var navConfig = { "context" : this,"callbackModelConfig" : {"navigateTofrmLogin" : true},"params" : {"dataTofrmLogin" : this.view.btnLogin.text}};
    var navManager = voltmx.mvc.getNavigationManager();
    navManager.navigate(navConfig);
  },
  
  navigateTofrmMypage : function(){
    var navConfig = { "context" : this,"callbackModelConfig" : {"navigateTofrmMypage" : true},"params" : {}};
    var navManager = voltmx.mvc.getNavigationManager();
    navManager.navigate(navConfig);
  }
 });
```
`context`には、先ほど同様`this`を指定します。

`callbackModelConfig`には、どの画面から来たかわかるようなパラメーターを指定します。
ログイン画面に遷移する関数には、`navigateTofrmLogin`の値をtrueに
マイページ画面に遷移する関数には、`navigateTofrmMypage`の値をtrueにすることで、
NavigationController側でどの画面から来たかを判別することが可能になります。

`params`は、次の画面に渡したい値がある場合に指定することが可能です。

関数が作成できたので、以下のように通常通りアクションを設定したら完了です！

|ログインボタンを押した時|マイページボタンを押した時|
|---|---|
|![スクリーンショット 0005-03-02 16.51.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/d4c07df3-1181-f56e-b297-1ad5926a481b.png)|![スクリーンショット 0005-03-02 16.51.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/9a60b589-502a-5a5b-58a6-9f136ee78f25.png)|

これで全て実装が完了したので、早速動作を見ていきましょう👀

# 実装結果
完成した画面がこちらです。
![ezgif-4-b8235477f2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/035fb2d1-f08b-6483-9151-f271aa28576c.gif)


メイン画面からホーム画面に遷移後、
ログインボタンが押されたらログイン画面に遷移し、
マイページボタンが押されたらマイページ画面に遷移したことがわかりますね！


# 最後に
Navigation Managerの機能を使って画面遷移を行う方法について紹介しました！

今回はシンプルな画面構成でしたが、
一般的なアプリの場合は1画面にいくつも遷移先があるため、
1つの場所で画面フローを管理できるようになることで保守も楽になると思います👀

また今回は1つのアプリ内のみでNavigation Managerを使ったロジック作成をしましたが、
他アプリの画面への遷移もNavigation Managerで一括管理することが可能です😳✨

複数アプリ間の画面遷移については、また次の機会に紹介したいと思います！

# 参考
https://opensource.hcltechsw.com/volt-mx-docs/95/docs/documentation/Iris/voltmx_ref_arch_api/Content/NavigationManager.html#navigation-manager