この記事では、Aura プログラミングモデルにおけるカスタムモーダル画面の作成方法をご紹介します。
モーダルの作成方法の種類
Aura でモーダル画面を作成するにはいくつかの方法がありますが、今回はよく使うであろう2通りをご紹介します。
それぞれに利点がありますが、実装方法が大きく異なるのでご注意ください。
-
lightning:overlayLibrary を使った方法
- 動的にモーダル画面を作成し、都度コンポーネントインスタンスの作成と削除を行う
- ヘッダー、ボディ、フッターをコンポーネント化するので、同様のモーダルを大量に作成する場合は再利用性が高まる
-
Salesforce Lightning Design System を使った方法
- 静的なモーダル画面を作成し、SLDS のクラスの付け替えで表示を制御する
- 一つのコンポーネントで完結するので、ちょっとしたモーダルを作りたいときに便利
lightning:overlayLibrary を使った方法
ボディとフッターが連携する
通常のモーダルの使い方として、ボディにフォームを配置しフッターに保存ボタンを配置することがあります。
しかし、lightning:overlayLibrary ではボディとフッターが別コンポーネントとなるため、互いに連携する手段が必要です。
例: フッターで「保存」が押されたら、ボディで保存処理をする
今回は アプリケーションイベント を使った連携方法も合わせてご紹介します。
イベントを作成
CustomModalEvent.evt
<aura:event type="APPLICATION" description="Custom Modal Event">
<aura:attribute type="String" name="type" /> <!-- SAVE/ERROR -->
</aura:event>
フッターを作成
CustomModalFooter.cmp
<aura:component>
<!-- Private Attributes -->
<aura:attribute access="private" type="Boolean" name="isDisabled" default="false" />
<!-- Registered Events -->
<aura:registerEvent type="c:CustomModalEvent" name="customModalEvent" />
<!-- Overlay Library -->
<lightning:overlayLibrary aura:id="overlayLib" />
<!-- User Interface -->
<div>
<lightning:button label="キャンセル" onclick="{!c.onCancelClicked}" disabled="{!v.isDisabled}" />
<lightning:button label="保存" variant="brand" onclick="{!c.onSaveClicked}" disabled="{!v.isDisabled}" />
</div>
</aura:component>
CustomModalFooterController.js
({
onCancelClicked: function(c, e, h) {
c.find('overlayLib').notifyClose();
},
onSaveClicked: function(c, e, h) {
c.set('v.isDisabled', true);
$A.get(`e.c:CustomModalEvent`)
.setParams({
type: 'SAVE'
}).fire();
}
});
ボディを作成
CustomModalBody.cmp
<aura:component>
<!-- Public Attributes -->
<aura:attribute access="public" type="String" name="lastName" />
<aura:attribute access="public" type="String" name="firstName" />
<aura:attribute access="public" type="String" name="email" />
<!-- Event Handlers -->
<aura:handler event="c:CustomModalEvent" action="{!c.onCustomModalEvent}" />
<!-- Overlay Library -->
<lightning:overlayLibrary aura:id="overlayLib" />
<!-- User Interface -->
<div>
<lightning:input type="text" label="姓" value="{!v.lastName}" />
<lightning:input type="text" label="名" value="{!v.firstName}" />
<lightning:input type="email" label="メール" value="{!v.email}" />
<lightning:spinner aura:id="spinner" class="slds-hide" variant="brand" size="large" />
</div>
</aura:component>
CustomModalBodyController.js
({
onCustomModalEvent: function(c, e, h) {
const eventType = e.getParams().type;
if (eventType === 'SAVE') {
h.showSpinner(c);
// TODO: ここで値の保存処理をする
// 保存が完了したらモーダルを閉じる
setTimeout($A.getCallback(function() {
h.hideSpinner(c);
c.find('overlayLib').notifyClose();
}), 3000);
}
}
});
CustomModalBodyHelper.js
({
showSpinner: function(c) {
const spinner = c.find('spinner');
$A.util.removeClass(spinner, 'slds-hide');
},
hideSpinner: function(c) {
const spinner = c.find('spinner');
$A.util.addClass(spinner, 'slds-hide');
}
});
CustomModalBody.css
.THIS {
position: relative;
}
モーダルを呼び出すには...
CustomModalButton.cmp
<aura:component access="global" implements="flexipage:availableForAllPageTypes,forceCommunity:availableForAllPageTypes">
<!-- Overlay Library -->
<lightning:overlayLibrary aura:id="overlayLib" />
<!-- User Interface -->
<lightning:button variant="brand" label="モーダルを開く" onclick="{!c.onButtonClick}" />
</aura:component>
CustomModalButtonController.js
({
onButtonClick: function(c, e, h) {
// モーダルボディのコンポーネントを作成
const createCustomModalBodyPromise = h.createComponent(c, h, 'c:CustomModalBody', {
lastName: '林',
firstName: '恵美',
email: 'ehayashi@example.com'
});
// モーダルフッターのコンポーネントを作成
const createCustomModalFooterPromise = h.createComponent(c, h, 'c:CustomModalFooter', {});
Promise.all([createCustomModalBodyPromise, createCustomModalFooterPromise])
.then(
$A.getCallback(function([customModalBody, customModaFooter]) {
c.find('overlayLib').showCustomModal({
header: '顧客情報の編集',
body: customModalBody,
footer: customModaFooter
});
})
)
.catch(function(reason) {
console.error(reason);
});
}
});
CustomModalButtonHelper.js
({
createComponent: function(c, h, componentDef, componentAttributes) {
return new Promise(function(resolve, reject) {
$A.createComponent(componentDef, componentAttributes, function(
newComponent,
status,
errorMessage
) {
if (status === "SUCCESS") resolve(newComponent);
else if (status === "ERROR") reject(errorMessage);
});
});
}
});
Salesforce Lightning Design System を使った方法
モーダル本体を作成
CustomModal.cmp
<aura:component access="global">
<!-- Public Attributes -->
<aura:attribute access="public" type="String" name="header" />
<aura:attribute access="public" type="String" name="lastName" />
<aura:attribute access="public" type="String" name="firstName" />
<aura:attribute access="public" type="String" name="email" />
<!-- Privte Attributes -->
<aura:attribute access="private" type="Boolean" name="showModal" default="false" />
<!-- Component Method -->
<aura:method name="open" action="{!c.onOpenCalled}" />
<!-- User Interface -->
<div>
<section role="dialog" tabindex="-1" class="{!'slds-modal' + if(v.showModal, ' slds-fade-in-open', '')}">
<div class="slds-modal__container">
<header class="slds-modal__header">
<lightning:buttonIcon size="large" class="slds-modal__close" iconName="utility:close" variant="bare-inverse" title="close" alternativeText="Close window" onclick="{!c.onCloseClicked}"/>
<h2 class="slds-text-heading_medium slds-hyphenate">{!v.header}</h2>
</header>
<div class="slds-modal__content slds-p-around_medium">
<lightning:input type="text" label="姓" value="{!v.lastName}"/>
<lightning:input type="text" label="名" value="{!v.firstName}"/>
<lightning:input type="email" label="メール" value="{!v.email}"/>
</div>
<footer class="slds-modal__footer">
<lightning:button label="キャンセル" onclick="{!c.onCancelClicked}" />
<lightning:button label="保存" variant="brand" onclick="{!c.onSaveClicked}" />
</footer>
</div>
<lightning:spinner aura:id="spinner" class="slds-hide" variant="brand" size="large" />
</section>
<div class="{!'slds-backdrop' + if(v.showModal, ' slds-backdrop_open', '')}"></div>
</div>
</aura:component>
CustomModalController.js
({
onOpenCalled: function(c, e, h) {
c.set('v.showModal', true);
},
onCloseClicked: function(c, e, h) {
c.set('v.showModal', false);
},
onCanceClicked: function(c, e, h) {
c.set('v.showModal', false);
},
onSaveClicked: function(c, e, h) {
h.showSpinner(c);
// TODO: ここで値の保存処理をする
// 保存が完了したらモーダルを閉じる
setTimeout($A.getCallback(function() {
h.hideSpinner(c);
c.set('v.showModal', false);
}), 3000);
},
})
CustomModalHelper.js
({
showSpinner: function(c) {
const spinner = c.find('spinner');
$A.util.removeClass(spinner, 'slds-hide');
},
hideSpinner: function(c) {
const spinner = c.find('spinner');
$A.util.addClass(spinner, 'slds-hide');
}
});
モーダルを呼び出すには...
CustomModalButton.cmp
<aura:component access="global" implements="flexipage:availableForAllPageTypes,forceCommunity:availableForAllPageTypes">
<!-- User Interface -->
<lightning:button variant="brand" label="モーダルを開く" onclick="{!c.onButtonClick}" />
<c:CustomModal aura:id="modal" header="顧客情報の編集" lastName="林" firstName="恵美" email="ehayashi@example.com" />
</aura:component>
CustomModalButtonController.js
({
onButtonClick: function(c, e, h) {
c.find('modal').open();
}
});