5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Visualforce] ページ読み込み時にapex:attributeの値をコントローラで使う方法

Last updated at Posted at 2020-05-22

TL;DR

apex:attributeの値をコントローラのコンストラクタで使用することはできません。
ページ読み込み時にapex:attributeの値をコントローラで使用する場合はgetter/setterまたはプロパティを使用します。

はじめに

Visualforceコンポーネントにapex:attribute要素を追加すると、Visualforceから呼び出すときに属性に値を設定できます。
下記の例ではVisualforceコンポーネントにカスタムのlogoLinkUrl属性を定義しています。

sample.page
<apex:page>
    <c:sampleHeader logoLinkUrl="https://www.google.com/"/>
</apex:page>
sampleHeader.component
<apex:component>
    <apex:attribute name="logoLinkUrl" type="String" description="ヘッダーアイコンのリンク先" />

    <header>
        <a href="{!logoLinkUrl}" class="logo"><img src="/img/logo214.svg"/></a>
    </header>
</apex:component>

このapex:attributeは、assignTo属性によってコントローラの変数に値を代入1することができます。
しかし、コンストラクタでこの値を使うと値が null となっていしまいます。
また、apex:component要素にはApexメソッドを呼び出すaction属性はありません。

Visualforceページにアクセスしたときの実行順序について

Visualforceページにアクセスした時、下記の順で処理が行われます。
Visualforceコンポーネントのコンストラクタ(2)は、apex:attributeassignTo(3)より先に実行されます。

  1. Visualforceページのコントローラのコンストラクタ。
  2. Visualforceコンポーネントのコンストラクタ。
  3. Visualforceコンポーネントのapex:attributeのassignTo属性(setterメソッド)。
  4. apex:pageコンポーネントのaction属性
  5. Visualforceページ・Visualforceコンポーネントのすべての式、getterメソッド、 setterメソッド
  6. (apex:formコンポーネントがある場合) ビューステートの作成
  7. HTMLの返却および、クライアントサイドの処理(javascriptなど)

Visualforceページ読み込み時にattributeの値をコントローラで使用する

attributeの値を使用するにはassignTo属性で指定したsetterを使用するか、getterで使用します。

「Visualforceページにアクセスしたときの実行順序について」でみたとおり、
assignToにより割り当てられている変数のsetterメソッドが呼び出され、
assignToのあとにgetterメソッドが使用されるからです。

下記では、選択リスト項目をラジオボタンで表示するVisualforceコンポーネントで例をあげます。
ATTRIBUTE002.PNG

getterメソッドの例 (選択リスト項目をラジオボタンで表示)

getterメソッド、getアクセス機構をもつプロパティの実行は、apex:attributeのassignToよりあとに行われます。
なのでgetterメソッドを使用すれば、ページ読み込み時にapex:attributeの値を使用することができます。

inputRadioDemo.page
<apex:page standardController="Account">
    <apex:form>
        <apex:pageBlock title="取引先" mode="edit">
            <apex:pageBlockButtons>
                <apex:commandButton action="{!quicksave}" value="保存" />
            </apex:pageBlockButtons>
            <apex:pageBlockSection title="ラジオボタンテスト" columns="1">
                <apex:outputField value="{!account.name}" />
                <apex:pageBlockSectionItem>
                    <apex:outputLabel value="区分" for="radio" />
                    <!-- ↓ ここでVisualforceコンポーネントを呼び出しています。 -->
                    <c:InputRadio value="{!Account.Type__c}" object="Account" field="Type__c" addNotSelect="true" id="radio"/>
                </apex:pageBlockSectionItem>
                <!-- ↓ 比較のための選択リストのinputFieldです。 -->
                <apex:inputField value="{!account.Industry}" />
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>
inputRadio.commponent
<!-- 選択リスト項目 ラジオボタン表示 -->
<apex:component controller="InputRadioCtrl">
    <apex:attribute name="value" type="String" assignTo="{!selectedValue}" description="" required="true"/>
    <apex:attribute name="addNotSelect" type="Boolean" assignTo="{!isAddNotSelect}" description="選択肢に未選択を表示する" default="false"/>

    <!-- ↓ ここで指定したSObjectField(選択リスト)の選択リスト値をコントローラで取得し、 apex:selectOptions で使用します。 -->
    <apex:attribute name="object" type="String" assignTo="{!objectStr}" description="SObject名をAPI参照名で指定" required="true"/>
    <apex:attribute name="field" type="String" assignTo="{!fieldStr}" description="選択リストの項目名をAPI参照名で指定" required="true"/>

    <apex:selectRadio value="{!value}" disabled="false" rendered="{!options.size!=0}" id="radio">
        <!-- ↓ apex:attributeの値をもとにコントローラで取得した値を使用しています -->
        <apex:selectOptions value="{!options}"/>
    </apex:selectRadio>
</apex:component>

InputRadioCtrl.cls
public with sharing class InputRadioCtrl {
    public String  selectedValue  { get; set; }
    public Boolean isAddNotSelect { get; set; }
    public String  objectStr      { get; set; }
    public String  fieldStr       { get; set; }

    // ↓ このgetterメソッドで、Visualforceページからapex:attributeを通して設定した値を使用して、選択肢を返しています。
    /** 選択肢の取得 */
    public List<SelectOption> getOptions() {
        Schema.SObjectField field = toSObjectField(objectStr, fieldStr);
        List<SelectOption> soList = new List<SelectOption>();
        if (field.getDescribe().isUpdateable()) {
            soList = getPickListOptions(field);
            if (String.isNotBlank(selectedValue) && !containsSelectOption(soList, selectedValue))  {
                // 無効な値が設定されているときは表示させる
                soList.add(new SelectOption(selectedValue, selectedValue));
            }
            if (isAddNotSelect) {
                soList.add(new SelectOption('', '未選択'));
            }
        }
        return soList;
    }

    /** SObjectField変換メソッド */
    private Schema.SObjectField toSObjectField(String objectName, String fieldName) {
        Schema.DescribeSObjectResult dsr = Schema.describeSObjects(new List<String>{objectName})[0];
        return dsr.fields.getMap().get(fieldName);
    }

    /** 選択リスト取得メソッド */
    private List<SelectOption> getPickListOptions(Schema.SObjectField field) {
        List<SelectOption> opList = new List<SelectOption>();
        for (Schema.PicklistEntry pe : field.getDescribe().getPickListValues()) {
            if (!pe.isActive()) { continue; }
            opList.add(new SelectOption(pe.getValue(),pe.getLabel()));
        }
        return opList;
    }

    /** 値が選択肢に含まれているか */
    private Boolean containsSelectOption(List<SelectOption> pOptions, String pValue) {
        List<String> values = new List<String>();
        for (SelectOption so : pOptions) {
            values.add(so.getValue());
        }
        return values.contains(pValue);
    }
}

setterメソッドの例 (選択リスト項目をラジオボタンで表示)

assignToで指定している変数のsetterメソッド、あるいはsetをもつプロパティを使用することで、ページ読み込み時にapex:attributeの値を使用できます。
下記ではsetをもつプロパティの例です。
getterメソッドの例とおなじ機能のものをsetをもつプロパティを使用して書き換えています。

inputRadioDemo.page
<apex:page standardController="Account">
    <apex:form>
        <apex:pageBlock title="取引先" mode="edit">
            <apex:pageBlockButtons>
                <apex:commandButton action="{!quicksave}" value="保存" />
            </apex:pageBlockButtons>
            <apex:pageBlockSection title="ラジオボタンテスト" columns="1">
                <apex:outputField value="{!account.name}" />
                <apex:pageBlockSectionItem>
                    <apex:outputLabel value="区分" for="radio" />
                    <!-- ↓ ここでVisualforceコンポーネントを呼び出しています。 -->
                    <c:InputRadio value="{!Account.Type__c}" field="Account.Type__c" addNotSelect="true" id="radio"/>
                </apex:pageBlockSectionItem>
                <!-- ↓ 比較のための選択リストのinputFieldです。 -->
                <apex:inputField value="{!account.Industry}" />
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>
inputRadio.commponent
<!-- 選択リスト項目 ラジオボタン表示 -->
<apex:component controller="InputRadioCtrl">
    <apex:attribute name="value" type="String" assignTo="{!selectedValue}" description="" required="true"/>
    <apex:attribute name="addNotSelect" type="Boolean" assignTo="{!isAddNotSelect}" description="選択肢に未選択を表示する" default="false"/>

    <!-- ↓ ここで指定したSObjectField(選択リスト)の選択リスト値をコントローラで取得し、 apex:selectOptions で使用します。 -->
    <apex:attribute name="field" type="String" assignTo="{!fieldStr}" description="項目を「ObjectApiName.FieldApiName」の形式で指定" required="true"/>

    <apex:selectRadio value="{!value}" disabled="false" rendered="{!options.size!=0}" id="radio">
        <!-- ↓ apex:attributeの値をもとにコントローラで取得した値を使用しています -->
        <apex:selectOptions value="{!options}"/>
    </apex:selectRadio>
</apex:component>

InputRadioCtrl.cls
public with sharing class InputRadioCtrl {
    public String             selectedValue  { get; set; }
    public Boolean            isAddNotSelect { get; set; }
    public List<SelectOption> options        { get; private set; }

    // ↓ assignToで代入されるプロパティです。
    // ここのsetアクセス機構で、設定された値(value)をつかって他の変数に値を設定しています。
    public String             fieldStr       { get; set {
        fieldStr = value;
        Schema.SObjectField field = toSObjectField(value);
        setSelectOption(field);
    }}

    /** 選択肢の設定 */
    private void setSelectOption(Schema.SObjectField field) {
        List<SelectOption> soList = new List<SelectOption>();
        if (field.getDescribe().isUpdateable()) {
            soList = getPickListOptions(field);
            if (String.isNotBlank(selectedValue) && !containsSelectOption(soList, selectedValue))  {
                // 無効な値が設定されているときは表示させる
                soList.add(new SelectOption(selectedValue, selectedValue));
            }
            if (isAddNotSelect) {
                soList.add(new SelectOption('', '未選択'));
            }
        }
        this.options = soList;
    }

    /** SObjectField変換メソッド */
    private Schema.SObjectField toSObjectField(String value) {
        List<String> objAndField = value.split('\\.');
        String objectName = objAndField[0];
        String fieldName  = objAndField[1];

        Schema.DescribeSObjectResult dsr = Schema.describeSObjects(new List<String>{objectName})[0];
        return dsr.fields.getMap().get(fieldName);
    }

    /** 選択リスト取得メソッド */
    private List<SelectOption> getPickListOptions(Schema.SObjectField field) {
        List<SelectOption> opList = new List<SelectOption>();
        for (Schema.PicklistEntry pe : field.getDescribe().getPickListValues()) {
            if (!pe.isActive()) { continue; }
            opList.add(new SelectOption(pe.getValue(),pe.getLabel()));
        }
        return opList;
    }

    /** 値が選択肢に含まれているか */
    private Boolean containsSelectOption(List<SelectOption> pOptions, String pValue) {
        List<String> values = new List<String>();
        for (SelectOption so : pOptions) {
            values.add(so.getValue());
        }
        return values.contains(pValue);
    }
}

参考

  1. Visualforceコンポーネントからコントローラに apex:attribute の value を渡す。その逆はできません。

5
2
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
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?