LoginSignup
2
1

More than 3 years have passed since last update.

Visualforceのレコード保存処理時、標準バリデーションエラーを回避して任意のactionを実行させる

Last updated at Posted at 2021-01-23

目的・目標

  • Visualforceのページメッセージを処理ごとに毎回クリアしたい
  • 確認画面、完了画面のないVisualforceページで編集画面のみでapex:pageMessagesを利用して視覚的に更新が完了・エラーした事を伝えたい
  • 処理実行前にVisualforce画面のapex:pageMessagesをクリアして任意の処理後に再度、完了・エラーを表示させたい

Before(保存1の処理)

Visualforceコード

<apex:pageBlockButtons location="bottom">
  <apex:commandButton value="保存1" action="{!save}" reRender="container" status="spinnerStatus"/>
</apex:pageBlockButtons>

動作画面

Before1.gif

  • 保存ボタンを押下したときロード画面が表示されているだけで更新されたのが認識しづらい

Try(保存2の処理)

Visualforceコード

<apex:pageBlockButtons location="bottom">
  <apex:actionFunction name="save1B" action="{!clearVfMsg}" oncomplete="return false;" reRender="container" />
  <apex:commandButton value="保存2" onclick="save1B();" action="{!save}" reRender="container" status="spinnerStatus"/>
</apex:pageBlockButtons>

動作画面

Before2.gif

改善

  • immediate="true"apex:actionFunctionにつけることで保存ボタン押下時にデータ型、桁数(Salesforce標準)、必須項目(Salesforce標準)のバリデーションエラーが発生した場合にメッセージクリア処理が実行されないことを回避しました

問題

  • メッセージクリア前にロード画面が入ってしまう
  • ボタンを連打するとapex:pageMessagesがバグで表示されない場合がある(キャプション 4回目の保存ボタン押下時)

After(保存3の処理)

Visualforceコード

<apex:pageBlockButtons location="bottom">
  <apex:actionFunction name="save1C" action="{!clearVfMsg}" oncomplete="save2C();" reRender="container" immediate="true"/>
  <apex:actionFunction name="save2C" action="{!save}" reRender="container" status="spinnerStatus"/>
  <apex:commandButton value="保存3" onclick="save1C(); return false;"/>
</apex:pageBlockButtons>

動作画面

After1.gif

改善

  • メッセージクリア後にロード画面が表示される
  • ボタンを連打してもapex:pageMessagesにバグが発生しない

学習したこと

  • immediate="true"apex:actionFunctionにつけることで保存ボタン押下時にデータ型、桁数(Salesforce標準)、必須項目(Salesforce標準)のバリデーションエラーが発生する場合でも任意の処理を先に実行させる事ができる
  • apex:actionFunctiononcompleteを利用して処理をメソッドチェーンさせることができる
  • メソッドチェーンさせることで任意の処理でロード画面などを実行させることができる

サンプルコード

Visualforceページ
<apex:page controller="VfTestCtrl" title="取引先責任者 編集" lightningStylesheets="true">
  <style>
    .spinnerBg{
        width: 100%;
        height: 100%;
        position: absolute;
        background-color: #000;
        opacity: 0.2;
        z-index: 999999;
    }
    .spinner{
        width: 100%;
        height: 100%;
        position: absolute;
        background-image: url("/img/loading32.gif");
        background-size: 16px;
        background-repeat: no-repeat;
        background-attachment: fixed;
        background-position: center;
        z-index: 9999999;
        opacity: 1;
    }
  </style>

  <apex:actionStatus id="spinnerStatus">
      <apex:facet name="start">
          <div class="spinnerBg"/>
          <div class="spinner"/>
      </apex:facet>
  </apex:actionStatus>

  <apex:form>
    <apex:outputPanel id="container">
      <apex:pageBlock title="取引先責任者 編集">
        <div style="min-height: 120px">
          <apex:pageMessages/>
        </div>
        <apex:pageBlockSection columns="1">
          <apex:inputField value="{!con.TestNum__c}"/>
        </apex:pageBlockSection>
        <apex:pageBlockButtons location="bottom">
          <apex:commandButton value="保存1" action="{!save}" reRender="container" status="spinnerStatus"/>
        </apex:pageBlockButtons>
        <apex:pageBlockButtons location="bottom">
          <apex:actionFunction name="save1B" action="{!clearVfMsg}" oncomplete="return false;" reRender="container" />
          <apex:commandButton value="保存2" onclick="save1B();" action="{!save}" reRender="container" status="spinnerStatus"/>
        </apex:pageBlockButtons>
        <apex:pageBlockButtons location="bottom">
          <apex:actionFunction name="save1C" action="{!clearVfMsg}" oncomplete="save2C();" reRender="container" immediate="true"/>
          <apex:actionFunction name="save2C" action="{!save}" reRender="container" status="spinnerStatus"/>
          <apex:commandButton value="保存3" onclick="save1C(); return false;"/>
        </apex:pageBlockButtons>
      </apex:pageBlock>
    </apex:outputPanel>
  </apex:form>
</apex:page>
VFコントローラ
public without sharing class VfTestCtrl {

    public Contact con { get; set; }
    private Id conId;

    /** 画面表示メッセージ */
    private static final String CONTACT_NOT_EXIST_MSG       = '取引先責任者が存在しません。';
    private static final String CONTACT_UPDATE_COMPLETE_MSG = '取引先責任者の更新が完了しました。';


    public VfTestCtrl() {
        this.conId = ApexPages.currentPage().getParameters().get('Id');

        List<Contact> conList = queryContact(conId);
        if (conList.isEmpty()) {
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, CONTACT_NOT_EXIST_MSG));
            return;
        }
        this.con = conList[0];
    }


    /** VFメッセージクリア処理 */
    public void clearVfMsg() {
        ApexPages.getMessages().clear();
    }


    /** 保存処理 */
    public void save() {
        List<Contact> conList = queryContact(conId);
        if (conList.isEmpty()) {
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, CONTACT_NOT_EXIST_MSG));
            return;
        }

        update con;
        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.CONFIRM, CONTACT_UPDATE_COMPLETE_MSG));
        return;
    }


    /** 対象の取引先責任者を取得 */
    private List<Contact> queryContact(Id contactId) {
        return [
            SELECT
                Id,
                TestNum__c
            FROM
                Contact
            WHERE
                Id = :contactId
        ];
    }
}

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1