Visualforceで（jQuery、Bootstrap）modalでちょっとしたリッチなUIを実現（いまさら感）

# 概要
　Visualforceの標準コンポーネント(\<apex:inputfield>など)を使って、Apexコントローラとのデータバインドをお任せしつつ、インターフェイスだけをリッチにする。下記のサンプルはBootstrapになっていますが、jquery uiやLightning Design Systemでも同様な実装が可能


# コード

### ポイント

- bootstrapのcssがきちんと適用できるようにstandardStylesheetsはfalseにしています  
  standardStylesheetsをfalseにできない場合は、bootstrap.cssのセレクターの詳細度をあげる  
  例）lessやSassでbootstrap.cssのすべてのセレクターの先頭に.user-contentsを付与する  
  ```
  .user-contents {
    @import (less) url("bootstrap.css");
  }
  ```
- standardStylesheetsをfalseにできない場合は、bootstrap.cssにprefixを適用してあげましょう
- 標準コンポーネントのstyleClass属性にcssフレームワーク用識別子を付与することで、標準コンポーネントも見栄え良くなる
- visualforceとcontrollerのデータバインディングは標準コンポーネントでしているため、別途実装は不要（手間いらず）
- modalの保存後に「取引先リスト」と「modal」の再描画(reRender)することで、ページ遷移が発生しない  
（保存後にmodalが自動で閉じる処理は入れてない）



```visualforce:text.vfp
<apex:page controller="TestPageController" standardStylesheets="false" showHeader="false">

<!-- 各種css/jsの読み込み -->
<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"/>

<!-- modal表示ボタン -->
<input type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#newAccountModal" value="新規取引先"/>

<!-- データ確認用のリスト -->
<apex:pageBlock id="accountList" title="取引先リスト">
    <apex:pageBlockTable value="{!accs}" var="acc" styleClass="table table-striped">
        <apex:column value="{!acc.name}"/>
        <apex:column value="{!acc.Site}"/>
        <apex:column value="{!acc.Phone}"/>
        <apex:column value="{!acc.Fax}"/>
    </apex:pageBlockTable>
</apex:pageBlock>

<!-- modal本体 -->
<div class="modal fade" id="newAccountModal" tabindex="-1" role="dialog">
  <apex:form id="addNewAccount">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
              <span aria-hidden="true">&times;</span>
            </button>
            <h4 class="modal-title">新規取引先</h4>
          </div>
          <div class="modal-body">
              <div class="form-group">
                <label for="newAccountName">取引先名</label>
                <apex:inputField value="{!newAcc.name}" styleClass="form-control"/>
              </div>              
              <div class="form-group">
                <label for="newAccountUrl">URL</label>
                <apex:inputField value="{!newAcc.Site}" styleClass="form-control"/>
              </div>              
              <div class="form-group">
                <label for="newAccountName">電話</label>
                <apex:inputField value="{!newAcc.Phone}" styleClass="form-control"/>
              </div>              
              <div class="form-group">
                <label for="newAccountName">Fax</label>
                <apex:inputField value="{!newAcc.Fax}" styleClass="form-control"/>
              </div>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">キャンセル</button>
            <apex:commandButton action="{!saveNewAcc}" reRender="accountList, addNewAccount" value="保存" styleClass="btn btn-primary" id="saveNewAcc"/>
          </div>
        </div><!-- /.modal-content -->
      </div><!-- /.modal-dialog -->
  </apex:form>
</div><!-- /.modal -->

</apex:page>
```

```apex:TestPageController.apxc
public with sharing class TestPageController{
  //確認用のリスト表示用
  public List<Account> accs {
    get{
       //リスト用
       this.accs = [Select Id, Name, Site, Phone, Fax from Account Order by CreatedDate desc Limit 10];
       return this.accs;
    }    
    set;
  }
    
  //新規Account用
  public Account newAcc {
    get {
      if(this.newAcc == null) {
        this.newAcc = new Account();
      }
      return this.newAcc;
    }
    set;
  }

  //保存ボタン
  public void saveNewAcc() {
    insert this.newAcc;
    this.newAcc = new Account();
  }
}
```

# ちょっとしたハマりポイント

 今回のサンプルではmodalで保存処理後にmodal自身の再描画を行っていますが、タグ構成が以下のようになっていると思わぬ動きします

```visualforce:text.vfp

<!-- 正しい -->
<div class="modal fade" id="newAccountModal" tabindex="-1" role="dialog">
  <apex:form id="addNewAccount">

↓

<!-- 誤り -->
<apex:form id="addNewAccount">
  <div class="modal fade" id="newAccountModal" tabindex="-1" role="dialog">

```

modalで保存後modal **内** の表示要素（\<apex:form id="addNewAccount">）を再描画したいが、上記の誤りのコードのようにmodal全体が再描画対象となり、modalが消える現象が発生します
なので、modal全体が再描画の対象にならないように前後のコードを確認することで思わぬ穴にハマらずに済みます


以上