function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
ruparuparuparupa 

Visualforce内でのJavaScriptの値取得方法について

お世話になっております。

<apex:dataTable>タグ内で特定のカラムに同じセレクトボックスを表示し、
そのセレクトボックスで選択された値を取得したいと考えております。

値の取得方法として、JavaScriptでテーブル内のカラムを順に読み込み、
カラム内の値をカンマなどでつなげてApexにhiddenで返そうと考えたのですが、
JavaScriptで<apex:dataTable>タグ内のセレクトボックスの選択値の取得方法がわかりませんでした。
 
public with sharing class testController {
    String[] countries = new String[]{};
            
    public PageReference test() {
        return null;
    }
            
    public List<SelectOption> getItems() {
        List<SelectOption> options = new List<SelectOption>();
        options.add(new SelectOption('US','US'));
        options.add(new SelectOption('CANADA','Canada'));
        options.add(new SelectOption('MEXICO','Mexico'));
        return options;
    }
            
    public String[] getCountries() {
        return countries;
    }
            
    public void setCountries(String[] countries) {
        this.countries = countries;
    }

    List<Account> accounts;

    public List<Account> getAccounts() {
        if(accounts == null) accounts = [select name, owner.name from account limit 5];
        return accounts;
    }
}
<apex:page controller="testController" >
<apex:form >
    <apex:dataTable value="{!accounts}" var="account" id="theTable" rowClasses="odd,even" styleClass="tableClass">
        <apex:column >
            <apex:outputText value="{!account.name}"/>
        </apex:column>
        <apex:column >
            <apex:selectList value="{!countries}" multiselect="false" size="1">
                <apex:selectOptions value="{!items}"/>
            </apex:selectList>
        </apex:column>
    </apex:dataTable>
    <apex:commandButton value="Test" action="{!test}" rerender="out" status="status" onclick="testScript(); "/>

<script type="text/javascript">
    function testScript () {
        var test = document.getElementById("{!$Component.theTable}");
        for (var i = 0; i < test.rows.length; i++) {
            alert(test.rows[i].cells[1].innerHTML);
            //ここでセレクトボックスで選択された値を取得したい
        }
    }
</script>

</apex:form>
</apex:page>

上記のようなコードで、JavaScript内で<apex:dataTable>タグ内のセレクトボックスで選択された値を
取得するにはどのようにすればよいでしょうか。

もしくはJavaScriptを使わずに実装できる方法などございますでしょうか。

ご存知のこと、お気づきの点などございましたら、ご教授頂けましたら幸いです。
どうぞよろしくお願いいたします。
Best Answer chosen by ruparupa
Taiki YoshikawaTaiki Yoshikawa
実際に値を使用するのはApex側だと思いますのでWrapperクラスを用意する方法が良いと思います。
サンプルコードです。

Visualforce Page
<apex:page controller="AccountTableViewController" id="page">
    <apex:form id="form">
        <apex:pageBlock id="block">
            <apex:pageMessages id="meg" />
            <apex:pageBlockButtons id="buttons">
                <apex:commandButton value="Click!!" action="{!doClick}" reRender="form" />
            </apex:pageBlockButtons>
            <apex:dataTable value="{!wrapperList}" var="item" id="dataTable">
                <apex:column >
                    <apex:inputCheckbox value="{!item.isChecked}" id="checked"/>
                </apex:column>
                <apex:column >
                    <apex:outputField value="{!item.account.Name}" id="accName"/>
                </apex:column>
            </apex:dataTable>
        </apex:pageBlock>
    </apex:form>
</apex:page>
Controller Class
public with sharing class AccountTableViewController {

    public List<AccountTableViewWrapper> wrapperList {get; set;}
    private List<Account> accounts {get; set;}

    public AccountTableViewController() {
        this.wrapperList = new List<AccountTableViewWrapper>();
        this.accounts = [SELECT Id, Name FROM Account ORDER BY Name ASC LIMIT 50];
        // Add List
        for (Account a : this.accounts) {
            this.wrapperList.add(new AccountTableViewWrapper(a));
        }
    }
    
    public void doClick() {
        for (AccountTableViewWrapper w : this.wrapperList) {
            // チェックボックス = Trueの判定
            if (w.isChecked) {
                ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO, w.account.Name));
            }
        }
    }
}
Wrapper Class
public with Sharing class AccountTableViewWrapper {

    public Boolean isChecked {get; set;}
    public Account account {get; set;}

    public AccountTableViewWrapper() {
        this.isChecked = false;
        this.account = new Account();
    }
    
    public AccountTableViewWrapper(Account account) {
        this.isChecked = false;
        this.account = account;
    }
}

Wrapperクラスを用意することで一つのチェックボックスと一つの取引先を紐付けることが可能です。
User-added image

 

All Answers

Taiki YoshikawaTaiki Yoshikawa
実際に値を使用するのはApex側だと思いますのでWrapperクラスを用意する方法が良いと思います。
サンプルコードです。

Visualforce Page
<apex:page controller="AccountTableViewController" id="page">
    <apex:form id="form">
        <apex:pageBlock id="block">
            <apex:pageMessages id="meg" />
            <apex:pageBlockButtons id="buttons">
                <apex:commandButton value="Click!!" action="{!doClick}" reRender="form" />
            </apex:pageBlockButtons>
            <apex:dataTable value="{!wrapperList}" var="item" id="dataTable">
                <apex:column >
                    <apex:inputCheckbox value="{!item.isChecked}" id="checked"/>
                </apex:column>
                <apex:column >
                    <apex:outputField value="{!item.account.Name}" id="accName"/>
                </apex:column>
            </apex:dataTable>
        </apex:pageBlock>
    </apex:form>
</apex:page>
Controller Class
public with sharing class AccountTableViewController {

    public List<AccountTableViewWrapper> wrapperList {get; set;}
    private List<Account> accounts {get; set;}

    public AccountTableViewController() {
        this.wrapperList = new List<AccountTableViewWrapper>();
        this.accounts = [SELECT Id, Name FROM Account ORDER BY Name ASC LIMIT 50];
        // Add List
        for (Account a : this.accounts) {
            this.wrapperList.add(new AccountTableViewWrapper(a));
        }
    }
    
    public void doClick() {
        for (AccountTableViewWrapper w : this.wrapperList) {
            // チェックボックス = Trueの判定
            if (w.isChecked) {
                ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO, w.account.Name));
            }
        }
    }
}
Wrapper Class
public with Sharing class AccountTableViewWrapper {

    public Boolean isChecked {get; set;}
    public Account account {get; set;}

    public AccountTableViewWrapper() {
        this.isChecked = false;
        this.account = new Account();
    }
    
    public AccountTableViewWrapper(Account account) {
        this.isChecked = false;
        this.account = account;
    }
}

Wrapperクラスを用意することで一つのチェックボックスと一つの取引先を紐付けることが可能です。
User-added image

 
This was selected as the best answer
Taiki YoshikawaTaiki Yoshikawa
ちなみにapex:repeatやapex:pageBlock / apex:dataTableなどリスト件数分繰り返し表示を行うタグを使用した場合、IDが連番となっています。

User-added image

次のような感じで要素の情報にアクセスできると思います。
document.getElementById('page:form:block:dataTable:' + i + ':checked');

JavaScript側で取得が必要な場合はこんな感じになると思います。
Taiki YoshikawaTaiki Yoshikawa
サンプルはチェックボックスで記載してしまいましたが、セレクトボックスでも同じようにできると思います。
ruparuparuparupa
Taikiさん

丁寧なご回答ありがとうございます!!
 
document.getElementById('page:form:block:dataTable:' + i + ':checked');
上記ですが、
document.getElementById('{!$Component.dataTable}' + i + '.checked');
のようにはできないですよね。
IDを指定して、構造を変えないようにして「{!$Component.〜」を使わないようにしないといけないですよね。

Wrapperクラスの方も確認してみます!!
ありがとうございます。
ruparuparuparupa
「{!$Component.〜」を使って実装できました。

下記のようにselectListnにIDをつけ、
<apex:selectList value="{!countries}" multiselect="false" size="1" id="selectListId">
for文内で下記のようにすることでセレクトボックスの選択値を取得できました。
txt = document.getElementById("{!$Component.theTable}" + ":" + i + ":selectListId");
selindex = txt.selectedIndex;
alert(txt.options[selindex].value);