読者です 読者をやめる 読者になる 読者になる

Labyrinth of Wisdom

-This is My Archive-


【Visualforce】入力フォームの行追加と行削除サンプル

Visualforceでの行追加・削除機能のサンプルです。 結構色んな要素を使ってて思ったよりもややこしかったので、忘れないうちにメモします。

行追加

これは思ってたよりも簡単に実装できます。

Accountのリスト型変数accountListを作成して、コンストラクタでAccount型の変数accountをnewしてaddします。 こうすることで画面に遷移した際に、空のテキストボックスが1行表示されます。

追加もこれと同じ要領で、追加ボタンを押した際に空のaccountがnewされて、accountListにaddされればいいのです。

ただし、今回のサンプルではテキストボックスの項目が必須になっている為、一工夫してやらないとうまく追加されません。 Visualforceの方で、追加ボタンのコードにimmediate="true"を設定してやることでこの問題を解決しています。

このimmediate="true"というのは全ての検証ルールをスキップすることが出来るという事を意味します。(デフォルトはfalse) immediate="true"を指定せずに追加ボタンを押すと、必須項目に値が入っていないと怒られてしまいます。

» 【Salesforce】apex:inputFieldの必須チェック回避【Visualforce】技術ブログ

行削除

こちらが色々な要素が入っていて意外とややこしいです。 まずパッと思いつくのは、accountListから要素を削除したらいけそうだな、となりますよね。

でもaccountListのインデックス(添え字)を指定してやらないと自分が削除したい行が消せないので、画面で指定した行番号を取得しないといけないという事になります。 なのでまず任意の行番号を取得するロジックが必要になります。

行番号指定

行番号指定には、Visualforceのvariableというコードを使用します。 これはVisualforce内で変数を設定できるコードみたいです。

pageBlockTableの上にvariableを置き、変数countを初期値0でセット。 pageBlockTable内で要素がループする前に再度variableを置き、countに1を加算。 これで一行目には0、二行目には1と、行番号がセットされます。

行番号送信

次に、この各行にセットされた数値をコントローラに渡してやる必要があります。 渡すタイミングとしては削除ボタンを押下した時なので、その辺りに仕込みます。

まずcommandButtonactionに行削除メソッドを指定、こちらにも同じ理由でimmediate="true"を指定します。 さらにreRenderに再描画したい範囲を指定してやります。 今回はform全体を再描画したいので、formのid値(form)を指定します。

commandButtonタグの間にparamをセットします。 paramnameに適当な値を指定、valueに行番号である変数countを指定します。 これで削除ボタンを押下した際にこのparamにセットした変数count送信されます。

行番号取得

コントローラで送信された行番号を取得していきます。

行削除メソッドでSystem.currentPageReference().getParameters().get('xxx')を使用して送信された行番号を取得します。 xxxの部分はparamnameで指定した値です。

取得した値をInteger型に変換して、変数rowNumberに代入します。 入力フォームが一行しかない場合は削除したくないので、accountListのサイズが1より大きい場合のみrowNumberのインデックスの要素を配列から削除します。

f:id:Labyrinth_of_Wisdom:20170208120534p:plain

サンプルコード

public class AddDeleteRowController {

    public Account[] accountList {get;set;}
    public Integer rowNumber {get;set;}

    // コンストラクタ
    public addDeleteRowController(){
        accountList = new List<Account>();
        Account account = new Account();
        accountList.add(account);
    }

    // 行追加
    public void addRow(){
        Account account = new Account();
        accountList.add(account);
    }

    // 行削除
    public void deleteRow(){
        // 行番号取得
        rowNumber = Integer.ValueOf(System.currentPageReference().getParameters().get('number'));
        // 一行以上の時に削除可能
        if(accountList.size() > 1){
            accountList.remove(rowNumber);
        }
    }

}
<apex:page controller="AddDeleteRowController" showHeader="false" sidebar="false" >
    <apex:pageBlock title="取引先">
        <apex:form id="form">
            <!-- 行追加ボタン -->
            <apex:commandButton value="追加" immediate="true" action="{!addRow}" />
            <!-- インデックス取得用の変数 -->
            <apex:variable value="{!0}" var="count"/>
            <apex:pageBlockTable value="{!accountList}" var="item">
                <!-- 行削除ボタン -->
                <apex:column headerValue="行操作">
                    <apex:commandButton value="削除" immediate="true" action="{!deleteRow}" reRender="form" >
                        <!-- 行のインデックスを送信する -->
                        <apex:param name="number" value="{!count}" />
                    </apex:commandButton>
                    <!-- ループするごとに+1 -->
                    <apex:variable value="{!count + 1}" var="count"/>
                </apex:column>
                <apex:column headerValue="名称">
                    <apex:inputField value="{!item.Name}"/>
                </apex:column>
            </apex:pageBlockTable>
        </apex:form>
    </apex:pageBlock>
</apex:page>