openui5sapui5

[SAPUI5/OpenUI5]大きくなりがちなViewのコードをFragmentsでパーツ化して賢くViewを構築する

May 06, 2014

11 min read

mitsuruogMitsuru Ogawa

先日、SAPUI5 のバージョンが 1.20 になりました。

SAPUI5 にて UI 部品が多い View を構築する場合、すぐに 1000 行を超えるような巨大 Javascript ファイルになってしまうのですが、Fragments と呼ばれる UI をパーツ化して再利用するための機能があります。

今回は、この Fragments について実際の利用シーンをイメージしながら紹介します。

目次

はじめに

最近、SAPUI5 を生の Javascript で書くと「}」とか「)}」とかしんどいので coffeeScript で書いて楽しています。また、すべてのソースコードをのせると非常に冗長なため、抜粋したソースコードを載せています。実際に動作するサンプルとソースコードは GIthub 上にありますので、そちらを参照してください。

サンプル http://mitsuruog.github.io/sapui5-showroom/#/fragment

ソースコード

1.Fragments とは

「Fragments」とは「断片、破片」という意味で、文字通り UI をパーツとして分割する機能です。公式ドキュメントはこちらです。

https://sapui5.hana.ondemand.com/sdk/#docs/guide/36a5b130076e4b4aac2c27eebf324909.html

SAPUI5 での Fragments とは View と同じようなものですが、Controller を作成する必要がありません。従って、基本的に UI 部分をパーツ化して再利用するために利用するものです。ロジックまで再利用したい場合は、素直に View にしてしまった方がいいでしょう。

2.基本的な使い方

Fragments を使うためには、まず「sap.ui.jsfragment」を継承してオリジナルの Fragments を定義していき、Fragments を View(以下、ownerView)にて呼び出して初期化し、View のコンテンツとして追加します。

まず、Fragments を定義していきます。

Edit.fragments.coffee

sap.ui.jsfragment "util.Edit",

  createContent: (oController) ->

    # ここに普通のJSViewのcreateContentと同様にUIコントロールを追加して
    # 最後にreturnします。

次に、ownerView 側で Fragments を呼び出します。

Fragments1.view.coffee

sap.ui.jsview "view.Fragment",

  getControllerName: ->
    "view.Fragment"

  createContent: (oController) ->

    @page = new sap.m.Page
      title: "Fragment Sample"

    # Fragmentsを呼び出します
    fragment = sap.ui.jsfragment "util.Edit", oController
    @page.addContent fragment

    @page

Fragments を初期化する際の第 2 引数の oController は、Fragment にて参照する Controller を渡してください(詳細は後述)。参照が無い場合は、当然 null となります。(渡した方が後のこととか考えると無難です。) また、この例の場合、SAPUI5 が呼び出す際のエイリアス名が「util.Edit」となるため、物理ファイル名と配置場所は「util/Edit.fragment.js」となります。〜fragments.js が接頭語だと思ってください。物理ファイルの配置場所とファイル名には特に注意が必要です。

基本的は使い方は以上です。

3.実際の利用シーン

では、実際のアプリケーションでの使いどころとしてはどのようなシーンがあるでしょうか。少し触って見た感じだと、以下の 2 つで使えそうです。

3.1 画面内での入力 UI と参照 UI の切り替え

このケースでは、1 画面で入力 UI と参照 UI の切り替え。用途としては、登録(変更)処理後に参照画面に切り替わるような、業務システムでよくあるシーンです。 SAPUI5 にてアプリケーションを構築した場合、MVC コンセプトに基づき View 部分と実際の表示データである Model は完全に分離され管理されています。 入力用と参照用の UI にて同じ Model を参照している場合、1 つの View 側で UI を切り替えた方がスマートだと最近考えています。

まず、参照用の Fragments を定義していきます。登録用の Fragments は先ほどの「Edit.fragments.coffee」を使います。

Detail.fragments.coffee

sap.ui.jsfragment "util.Detail",

  createContent: (oController) ->

    # ここに普通のJSViewのcreateContentと同様にUIコントロールを追加して
    # 最後にreturnします。

最後に、controller にて Fragments 呼び出し処理を行います。

Fragments2.controller.coffee

sap.ui.jsview "view.Fragment",

  getControllerName: ->
    "view.Fragment"

  createContent: (oController) ->

    @page = new sap.m.Page
      title: "Fragment Sample"

    # Fragmentsを呼び出します
    # -> controllerで呼び出すようにします
    #fragment = sap.ui.jsfragment "util.Edit", oController
    #@page.addContent fragment

    @page

次に、ownerView 側のボタンで UI の切り替えを行うため、ownerView で行っていた Fragments 呼び出し処理を、controller で行うようにします。

Fragments2.view.coffee

jQuery.sap.require "sap.m.MessageToast"

sap.ui.controller "view.Fragment",

  _fragments: {}
  _mode: "Detail"

  _getFragments: (name) ->
    #fragmentsを取得してキャッシュ
    unless @_fragments[name]
      @_fragments[name] = sap.ui.jsfragment "util.#{name}", @
    @_fragments[name]

  _toggleFragment: (name) ->
    fragment = @_getFragments name
    container = sap.ui.getCore().getElementById "fragContainer"
    #コンテナの0番目にfragmentsで取得したFormを追加します
    #[MEMO]ここではViewの中のContentはfragmentsのみの想定で書いています
    #[MEMO]Contentが複数ある場合は、removeContentとinsertContentのindexを変更してください
    container.removeContent 0
    container.insertContent fragment, 0
    @_mode = name

  onInit: ->
    @_toggleFragment "Detail"

  #入力用と参照用のFormを切り替る処理
  pressedToggle: (oEvt) ->
    if @_mode is "Detail"
      @_toggleFragment "Edit"
    else
      @_toggleFragment "Detail"

ここでの removeContent と insertContent は View の中で Content となる UI パーツが Fragments1 つのみの前提で書いています。 また、Fragments を切り替えるコンテナを作成して、固有の ID を振って Javascript 側からいつでもフックできるようにするといいでしょう。

3.2 ダイアログ UI の再利用

このケースでは、選択用などのダイアログ UI を再利用します。単純なものではなく少し UI パーツが多いダイアログを再利用するとさらに効果的です。 先ほどと同様にダイアログ用の Fragments を定義していきます。

Dialog.fragments.coffee

sap.ui.jsfragment "util.Dialog",

  createContent: (oController) ->

    dialog = new sap.m.Dialog
      title: "Dialog"
      content: [

        #入力用のFragmentsを再利用します

        sap.ui.jsfragment "util.Edit", oController
      ]
      beginButton: new sap.m.Button
        type: "Accept"
        text: "OK"
        press: [oController.pressedOk, oController]
      endButton: new sap.m.Button
        text: "NG"
        press: [oControl

ダイアログの中身のコンテンツは先ほど定義した Edit.fragments.js を再利用しています。こんなところでも Fragments いい仕事しています。

Fragments 側から Controller の function を呼び出していると思います。 これは、Fragments を初期化する際に Controller の参照を渡す事で、Fragments 側から OwnerView の Controller の function を呼び出すことが出来ます。

この場合、OwnerView 側で Fragments が使う function を知っていて実装する必要があります。Java でいうインターフェースと同じような感覚なのですが、いかんせん動的型付け言語なのでチェックが緩いです。Controller に function が存在しない場合は当然、実行時に落ちます。 次に ownerView の controller にて Fragments を呼び出します。ownerView にてダイアログを開くボタンを押した際にダイアログを open します。

Fragments3.controller.coffee

jQuery.sap.require "sap.m.MessageToast"

sap.ui.controller "view.Fragment",

  _fragments: {}

  _getFragments: (name) ->
    #fragmentsを取得してキャッシュ
    unless @_fragments[name]
      @_fragments[name] = sap.ui.jsfragment "util.#{name}", @
    @_fragments[name]

  onInit: ->

  #ダイアログを表示します
  openDialog: (oEvt) ->
    dialog = @_getFragments "Dialog"
    dialog.open()

  #ダイアログでOKをPressした時の処理
  pressedOk: (oEvt) ->
    oEvt.getSource().getParent().close()
    sap.m.MessageToast.show "pressed OK"

  #ダイアログでNGをPressした時の処理
  pressedNg: (oEvt) ->
    oEvt.getSource().getParent().close()
    sap.m.MessageToast.show "pressed NG"

Fragments にて OK/NG ボタンを押した場合の処理は、Controller に記述して処理させています。

4.まとめ

Fragments とは以前から SAPUI5 にあった機能ですが、「Experimental(実験的)」な機能に分類されていました。1.20 からはめでたく Experimental でなくなったので、やっと実戦で投入できるようになりました。

SAPUI5 にて UI 部品が多い View を構築する場合、すぐに 1000 行を超えるような JS ファイルになってしまうのですが、このように Fragments を使うことで UI 部品をパーツで切り離して利用できるようになります。
(行数が多いのは SAPUI5 に限ったことではありません、Javascript で View を作成する UI フレームワークはそうなりやすいです。)

また、UI を部品化することでアプリケーション内での再利用が進み、開発効率と品質面で一定のアドバンテージがあると思います。 巨大化しやすい View をいかにパーツ化して再利用しながらアプリケーションを構築していくのが、SAPUI5 に限らず UI フレームワークでアプリケーションを構築する際のポイントだと最近感じています。