How to create new own controls in OpenUI5(Part 2)
前回に引き続き、OpenUI5 にてカスタム UI コントロールを作成する方法の後編です。今回のパートは「既存の UI を拡張する」方法についてです。
今回のデモはこちらで参照できます。 http://mitsuruog.github.io/sapui5-showroom/#/controls
こちらの公式ページの内容をもとに書いています。 Developing UI5 Controls in JavaScript
目次
1. 既存 UI コントロールの継承
既存の UI コントロールを継承した新しい UI コントロールを作成していきます。基本的には extend することで継承が可能です。 下の例は、sap.m.Input を継承して「mitsuruog.NoisyInput」という UI コントロールを作成しています。
jQuery.sap.declare "com.mitsuruog.sapui5.showroom.controls.NoisyInput"
sap.m.Input.extend "mitsuruog.NoisyInput",
metadata: {}
renderer: {}
2. 新規機能の追加
継承した UI コントロールに対する新機能の追加は、新しい UI コントロールの追加と変わりません。 こちらは先ほどの mitsuruog.NoisyInput 新しい機能を追加する例です。
NoisyInput は、focusin した際に UI コントロールを左右にアニメーションする新しい Input コントロールです。外部からbeQuiet=true
を受け取ることで静かになります。
sap.m.Input.extend "mitsuruog.NoisyInput",
metadata:
properties:
beQuiet:
type: "boolean"
defaultValue: false
onfocusin: (evt) ->
unless @getBeQuiet() then @addStyleClass "shake"
onfocusout: (evt) ->
unless @getBeQuiet() then @removeStyleClass "shake"
既存 UI コントロールの既存機能(イベントハンドラなどの関数)を上書きする場合は、同名の function を宣言した上で継承元の prototype 関数を呼び出します。
sap.m.Input.extend "mitsuruog.NoisyInput",
metadata:{}
# 省略...
init: ->
sap.m.Input.prototype.init.apply @, arguments
onBeforeRendering: ->
sap.m.Input.prototype.onBeforeRendering @, arguments
上の例は既存の init と onBeforeRendering に対して機能を追加する例です。この例では実際に機能を追加していませんが、雰囲気は掴めると思います。
3. レンダラの変更
新しい UI コントロールの新しい UI を作成します。基本的には renderer を定義して、中で既存 UI コントロールの renderer を呼び出しすれば良いです。
sap.m.Input.extend "mitsuruog.NoisyInput",
metadata:{}
# 省略...
renderer: (rm, control) ->
rm.write "<div class='mitsuruogNoisyInput'>"
sap.m.InputRenderer.render.apply @, [rm, control]
rm.write "</div>"
ただし、実態は既存 UI コントロールの renderer がどのように実装されているかに依存している場合が多く、確実に実装するためには OpenUI5 側のソースを一度確認したほうがいいです。
OpenUI5 のコンロールの場合は、コントロールクラスの近くに「〜Renderer-dbg.js
」があるのでこれを見ます。(-dbg)が付いているものが minify されていないものです。
例) Input.js -> InputRenderer-dbg.js Label.js -> LabelRenderer-dbg.js
既存の renderer を確認すると、外部から renderer のライフサイクルに対してフックするための I/F を備えているもの(sap.m.Input など)があります。 その場合は新しい UI コントロールの renderer 内から I/F 名を指定して機能を追加していきます。
次の例では、既存の addInnerStyles が実行される前に、Input コントロールの外見を変更する指定をしています。
(inner や outer があるのは、OpenUI5 の UI コントロールは外側を div コンテナで囲う場合が多いからです。外側のコンテナを outer、内側の UI コントロールを inner と表現しています。)
sap.m.Input.extend "mitsuruog.NoisyInput",
metadata:{}
# 省略...
renderer:
addInnerStyles: (rm, control) ->
rm.addStyle "background-color", "#23AC0E"
rm.addStyle "border-radius", "7px"
ただし、既存の renderer を変更することは良くありません。既存の renderer の前後に機能を追加するか、フック用の I/F を利用するようにしてください。 既存の renderer を変更する必要な場合は、継承せず新規で UI コントロールを作成した方がいいと思います。
4. 配布、利用
配布方法は、新規 UI コントロールを作成する場合と変わりありません。
継承元のクラスがロードされていないケースを想定し、予防的にjQuery.sap.require
にてクラスをロードする記述を書いておいた方がいいと思います。
5. まとめ
2 回に分けて OpenUI5 にて新しい UI コントロールを作成する方法を紹介しました。 OpenUI5 はフレームワーク側の仕組みが複雑であるために、正しい方法を理解せず、カスタムしようとすると必ず手痛い失敗をします。(経験談)
OpenUI5 多くの優れた UI コントロールを持っているため、本来であれば無理にカスタムせず、OpenUI5 のコンポーネントの機能の範囲内で UI を構築していく方がベストですが、カスタムの方法も知っておくと、一気に利用の幅が広がると思います。