パンくずリストのコンポーネントを作ってみよう！

# 目次
1. はじめに
1. 完成イメージ
1. コンポーネントのテンプレート作成方法
1. コンポーネントの活用方法
1. レイアウト変更方法
1. まとめ


# はじめに
前章でコンポーネントの概要について学びましたので、
今回は、実際にコンポーネントを作ってみたいと思います😊

作成するコンポーネントは、
Webアプリ等で画面の上部に表示される以下のようなパンくずリストです。
![スクリーンショット 0004-08-24 10.11.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/8b917201-5a9c-524a-7719-d6508acd2f1b.png)
（参考：https://www.asobou.co.jp/blog/web/breadcrumb-list）

一度コンポーネントを作成すれば、
新たにWidgetやロジックを書く必要がなく追加や修正が簡単になります✨

では、早速作っていきましょう！

# 完成イメージ

今回の完成イメージは以下の通りです👀

![イメージ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/f97d69ac-53c7-b5f4-af77-e624f0b60b5c.gif)

画面を遷移するごとに、パンくずリストの値が変更され、
パンくず内のリンクをクリックすると対象画面に遷移できていることがわかると思います😊

早速実装方法を紹介していきます！

まず、コンポーネント のテンプレートを作成していきましょう。

# コンポーネントのテンプレート作成

## レイアウト作成
まずはパンくずリストのベースとなるレイアウトを作成していきましょう。

Visualizerの左メニューにあるTemplatesタブに切り替えます。
![スクリーンショット 0004-08-23 17.15.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/ea5e332b-07ef-f9a0-b387-c02cfde552da.png)


Components部分を右クリックしたら、
Newを選択し、with Contractを選択します。

:::note 
w/o Contract と with Contractの違いについては
下記の記事を参考にしてください。
▶︎[Kony Visualizerでコンポーネントを作成する](https://qiita.com/Kony_Team/items/a25b322d9524f9f1ac92)
:::
![スクリーンショット 0004-08-23 17.15.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/2cfd1cfd-acfc-4d1e-da4e-5c5dc79641f8.png)

ポップアップが開くので、
NameSpace、Name、Versionなどの情報を入力し、OKボタンをクリックするとコンポーネントが作成されます。
![スクリーンショット 0004-08-23 17.16.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/0aa4f0ae-7fac-27c5-8239-a568830590c7.png)

これで、コンポーネントのベースが作成できました。

次に、作成したコンポーネントの中に
Widgetを配置して、パンくずリストのUIを作成していきます。

今回、このようにWidgetを配置をしました。

![スクリーンショット 0004-08-24 10.23.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/5623f9e3-55db-d727-9336-f500fe516a44.png)

flxTemplateは、Breadcrumbの全てのパーツを複製するテンプレートで、
ページナビゲーション名を表示するための `btnTitle`、
ページナビゲーション名を表示するがボーダーを下側に持ってくる 
`btnTitleUnlink`、ページナビゲーション名を区別するために画像の矢印を表示する `imgArrowRight` が含まれています。

flxContentsは、flxTemplateのクローンを格納するコンテナで、
パンくずのパーツはすべてここ（flxAreaの中）に格納されます。

これでパンくずコンポーネントのベースは完成となります。
次に、コンポーネントのManage Propertiesを編集し、フォームに公開する値を定義していきます。


## フォームに公開する値の管理

コンポーネントのManage Propertiesという機能では、
フォームに公開する値を定義することができます。

今回パンくずリストコンポーネントでは、
フォームから、パンくずリストを表示するために必要ないくつかの値を渡し、
コンポーネント側でその値を元にWidgetの作成やアクション定義の処理を行います。

このような流れで処理が行われるようにします。
![スクリーンショット 0004-08-24 14.24.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/f98288d5-b5fd-15a2-21e0-80f86dcbfe6b.png)

フォームから渡す値を指定できるようにしたいので、
コンポーネントのManage Properties機能を使ってフォームに公開する値を設定していきましょう！

まず、Breadcrumbコンポーネントを選択した状態で
右メニューのPROPERTIES->Componentタブを選択したら、
Manage Propertiesボタンをクリックしてください。

![スクリーンショット 0004-08-23 17.23.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/ccdeef17-12c4-95b4-0f9b-e2b1f44731a5.png)

Manage Propertiesのポップアップが表示され、
Pass ThroughタブとCustomタブが用意されています。

2つの違いについては、以下リンクをご参照ください。
▶︎[Kony Visualizerでコンポーネントを作成する/プロパティ・メソッド・イベントの共有](https://qiita.com/Kony_Team/items/a25b322d9524f9f1ac92#3-%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%AE%E5%85%B1%E6%9C%89)

今回は、Widgetではなくdataを扱えるようにしたいため、
Customタブで値を設定していきます。

+ボタンをクリックすると、リストプロパティに新しいレコードが追加されます。
![スクリーンショット 0004-08-23 17.24.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/4e146f34-d254-34c2-a68a-83a35251971d.png)

新しいレコードが追加されたら、コントローラに公開する値を設定していきます。
今回は、このように設定しました。

![スクリーンショット 0004-08-24 11.36.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/e600f62f-cba4-dee1-51b7-63fe44d8b003.png)
Default Valueには、以下の値を設定しています。
`[{"name":"ホーム","page":"frmHome","disabled":false}]`

各値の詳細については以下をご参照ください。
▶︎[Kony Visualizerでコンポーネントを作成する](https://qiita.com/Kony_Team/items/a25b322d9524f9f1ac92#3-%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%81%AE%E5%85%B1%E6%9C%89)

すべて入力したら、Applyをクリックします。

ここで設定したプロパティはComponentタブに表示され、
Controllerには自動的に`defineGetter`と`defineSetter`が生成されます。

![ezgif-3-584e886676.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/991cddb6-9d66-9a0a-35ad-1cd6f1f0a8bd.gif)


## レイアウト処理ロジック作成
次に、BreadcrumbControllerに移動して、
Manage Propertiesで定義した値をフォームから受け取り、
コンポーネントを介してフォームに画面を表示するロジックを作成していきましょう:v:

以下のようにロジックを作成しました。
```BreadcrumbController.js
_onLayout: function(value) {
    var self = this;
    // 要素を削除
    this.view.flxArea.removeAll();
    self.view.btnTitle.hoverSkin = self.view.btnTitle.focusSkin;
    if (value && Array.isArray(value)) {
        value.map((v, index) => {
            if (v.disabled !== true) {
                //リンクありの場合
                btnObj = self.view.btnTitle.clone("btnBreadcrumb" + index);
                btnObj.skin = 'sknBtnSmalLink'
                btnObj.text = v.name;
                //画面遷移アクションを作成
                btnObj.onClick = function () {
                    const page = new kony.mvc.Navigation(v.page);
                    page.navigate();
                };
                self.view.flxArea.add(btnObj);
            } else {
                //リンクなしの場合
                btnObj = self.view.btnTitleUnlink.clone("btnBreadcrumb" + index);
                btnObj.skin = 'sknBtnSmalUnLink'
                btnObj.text = v.name;
                self.view.flxArea.add(btnObj);
                //画面遷移アクションは無し
            }

            if (index < value.length - 1) {
                var imgObj = self.view.imgArrowRight.clone("imgBreadcrumb" + index);
                imgObj.src = self.view.imgArrowRight.src;
                self.view.flxArea.add(imgObj);
            }
        });
    }
}
```

この関数ではフォームから配列データを受け取り、
受け取った値に応じてWidgetを作成する処理を行います。

まずパラメータが正しいか、データが配列かどうかをチェックし、
もし正しければ、配列をループし、アイテムに対応する値を持つボタンを作成します。

配列データの`disabled`（リンクを無効にする値）の値がfalseであれば、
リンク付きのボタンを生成し、
そうでなければリンクなしのボタンを生成する流れになっています。

以下から、よく使用されるメソッドの紹介を行います👀


.
.

**clone()**
コンテナWidgetに対して`clone()`メソッドを使うと、
**対象のコンテナWidgetを複製することができます。**

例：`self.view.btnTitle.clone("btnBreadcrumb"+index);`
と指定すると、btnTitleのWidgetが複製される。

また、オプションとして、
()内に値を入れると、複製されたWidgetのID名は、
()内に入れたID + コピー元のWidgetIDの名前で作成されます。
上記の例で言うと、`btnBreadcrumb1btnTitle`という名前でWidgetが作成されます。

反対に、()に何も入れない場合、<font color = red>
**複製されたWidetはコピー元のWidgetと同じIDで作成されてしまい、
予期せぬ動作をしてしまう可能性がある**</font>ため、
必ず()内にWidgetIDを渡してあげるようにしましょうね👀

.
.


ボタンWidgetが複製された後は、
`btnObj.skin = 'スキン名'`
で、Skinを指定し、
`btnObj.text=v.name;`
で、フォームから渡ってきた「name」の値を元に、パンくずリストに表示するテキストを指定します。
`btnObj.onClick = function()`
で、フォームから渡ってきた「page」の値を元に、
パンくずのリンクをタップした時にどの画面に遷移させるかフォーム名を指定します。

最後に、`self.view.flxArea.add(btnObj)`
で、`flxArea`のWidget内に複製したボタンWidgetを配置するよう処理が行われています。

これを配列分ループして実行しています。


## 初期表示制御

レイアウト処理のロジックが作成できたら、
初期表示時の表示ロジックを定義します。

コンストラクタ関数では、`flxTemplate`を非表示にします。
`flxTemplate`はボタンとimageArrowを含むだけなので、
画面に表示する必要はなく、`flxContents`（パンくずを含むフレックス）を画面上に表示させるようにします。

```BreadcrumbController.js
constructor: function(baseConfig, layoutConfig, pspConfig) {
    this.view.flxContents.isVisible=true;
    this.view.flxTemplate.isVisible=false;
},
```

これでコンポーネントのテンプレートの作成が完了しました！

実際にフォームに作成したコンポーネントを追加し、
どのように設定を行うかみていきましょう:relaxed:

# コンポーネントの使い方

## フォームの作成
まず、パンくずリストを表示するフォームを作成します。

今回は、3画面作成しました。
![スクリーンショット 0004-08-24 11.56.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/18ba47c5-902a-0f18-a41d-caef8d451b81.png)

次に各画面にパンくずリストを設置したいので、
作成したコンポーネントを各フォームに追加していきましょう。

## フォームにコンポーネントを追加
コンポーネントを入れたいフォームを開いた状態で、
TemplateタブをクリックしComponents一覧から挿入したいコンポーネントを右クリックします。
「Insert Into」をクリックすると、フォームに追加されます。
![ezgif-3-1245b0ea04.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/0a8226e2-a1b1-0722-c334-c858dcae4cc7.gif)

追加されました。
![スクリーンショット 0004-08-24 12.02.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/7d92c48f-f083-284b-d541-daf0844a085b.png)

同様の手順で、全ての画面にコンポーネントを追加しましょう。

## コンポーネントに渡す値を設定
次に、各フォームからパンくずリストコンポーネントに渡す値設定していきましょう。

パンくずリストコンポーネントをクリックし、
PROPERTIES->Componentタブを選択すると、
Generalの下に[フォームに公開する値の管理](#フォームに公開する値の管理)で
作成したdataプロパティが確認できるかと思います。

dataプロパティの「Edit」ボタンクリックして、データの値を変更していきましょう。
![スクリーンショット 0004-08-24 15.20.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/d60bcdc8-22a2-1a2a-6f3c-a7eca9230310.png)

デフォルトの値は、Manage PropertiesのDefault Valueで設定した値がJSON形式で表示されます。
![スクリーンショット 0004-08-24 15.30.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/a3246161-f0a9-ae57-0528-a0f4886982eb.png)


例として、
商品詳細画面のパンくずリストのデータを編集する場合、
JSONデータを以下のように変更します。

```data.json
[{"name":"ホーム","page":"frmHome","disabled":false}, 
{"name":"商品一覧","page":"frmProduct","disabled":false},
{"name":"商品詳細","page":"frmProductDetail","disabled":true}]
```

設定が終わったら「Done」をクリックします。

他の画面も同様に値の設定を行ったら完了です！


Live Previewで実際の動作を見てみましょう。

![イメージ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/fcc8098f-0fd4-9c67-017e-171940a5d7a1.gif)

完成イメージの通り、
画面遷移するとパンくずリストの表示が変わり、
リンクをクリックするとその画面に遷移できていることがわかりますね🎉

コンポーネントを作成しておくだけと、
各フォームで値を設定していくだけでとっても簡単に実装することができます！

**難しい知識を必要とせず、誰でも開発ができるような仕組み**ができるため、
開発のスピードが爆上がりしますよ:relaxed:

# 補足：コンポーネントの色を変更する方法

もし、開発途中で急な仕様変更があり、
全ての画面でレイアウトを変更しなくてはいけない時ありますよね。。:frowning2:💦

途中でレイアウトを変更する場合でも、
コンポーネントを使用していれば簡単に修正ができます！！

例えば、以下のように
🥸「全体的にパンくずリストの背景を青色にしてほしいな〜〜」
という要望があったとします。
![スクリーンショット 0004-08-24 15.36.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/ce7f9981-a758-17c5-4fb5-dce056b6fdb1.png)


まずTemplateタブで対象のコンポーネントを開き、
変更したいWidgetを選択します。

今回背景を変更するため、
`Breadcrumb`のWidgetを選択した状態で、
BackGroundカラーを変更します。

![スクリーンショット 0004-08-24 12.25.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/8ec77044-d93f-c849-d1f0-11da7874109a.png)
青色に変更してみました。

早速ビルドして確認してみましょう。
![ezgif-3-ff3ed1a615.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592264/dca03e39-de28-ecdf-28fd-c098a101785e.gif)

全ての画面でパンくずリストの背景が青色に変わりましたね！
レイアウト変更はこれで完了です。

コンポーネントのベースを変更するだけで、
コンポーネントを入れている全てのフォームでこの変更が適用されるため、
レイアウトの変更もとっても楽ちんですね:relaxed:⭐️

# まとめ

最後にまとめです！
コンポーネントを作成することで、以下のようなメリットがあります。

:::note 
コンポーネントを使うメリット

**・処理を共通化することで、追加・修正等があった場合でも、
　開発作業の手間を省くことができる**
**・レイアウトを共通化することで、見た目が統一される**
**・処理が簡単になるため、誰でも開発に参加することができる**

:::

今回作成したソースコードと、サンプルプロジェクトは一番下に載せておきます。
途中でつまづいてしまった方は、参考にしてみてくださいね！


# 次の記事
次は、コンポーネントを公開したりダウンロードしたりできるプラットフォーム、
Temenos Forge（旧Kony Marketplace）の概要について説明していきます！  

https://qiita.com/Kony_Team/items/a2208485463ed2b25c34


記事一覧：
https://qiita.com/Kony_Team/private/4c922fa016ce95c58406


# 全体のコード
```BreadcrumbController.js
define(function() {

	return {
		constructor: function(baseConfig, layoutConfig, pspConfig) {
			this.view.flxContents.isVisible=true;
            this.view.flxTemplate.isVisible=false;
		},
		//Logic for getters/setters of custom properties
		initGettersSetters: function() {
            defineGetter(this, 'data', () => {
                return this._data;
            });
            defineSetter(this, 'data', value => {
                this._onLayout(value);
                this._data = value;
            });
        },
        _onLayout:function(value){
          var self = this;
          // 要素を削除
          this.view.flxArea.removeAll();
          self.view.btnTitle.hoverSkin=self.view.btnTitle.focusSkin;
          if(value && Array.isArray(value) ){
            value.map((v,index)=>{
              if(v.disabled !== true){
                btnObj =  self.view.btnTitle.clone("btnBreadcrumb"+index);
                btnObj.skin = 'sknBtnSmalLink'
                btnObj.text=v.name;
                btnObj.onClick = function(){
                  const page = new kony.mvc.Navigation(v.page);
                  page.navigate();
                };
                self.view.flxArea.add(btnObj);
              }else{
                btnObj =  self.view.btnTitleUnlink.clone("btnBreadcrumb"+index);
                btnObj.skin = 'sknBtnSmalUnLink'
                btnObj.text=v.name;
                self.view.flxArea.add(btnObj);
              }
              
              if(index<value.length-1){
                var imgObj =self.view.imgArrowRight.clone("imgBreadcrumb"+index);
                imgObj.src=self.view.imgArrowRight.src;
                self.view.flxArea.add(imgObj);
              }
            });
          }
        }
	};
});


```
サンプルプロジェクトはこちら
▶︎https://github.com/konyqiitadev/Answer3

# 参考
・[【公式】Create a Component](https://docs.kony.com/konylibrary/visualizer/visualizer_user_guide/Content/C_CreatingComponent.htm)
・https://www.asobou.co.jp/blog/web/breadcrumb-list