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
muromuromuromuro 

VisualforceからApexへページ遷移なしで引数を渡すには

初投稿です。ご覧いただきありがとうございます。
社内で勉強中なのですが、先輩方でも打開できなかったので、お知恵をお貸しいただけると幸いです。

VisualforceとApexを使用し、社内のソフトウェア・備品とそれに関連付けられたPCを表示するシステムを作っています。
Visualforce(viewSoftwareFixture.vfp)からApex(getPC.apxc)に備品名(SoftwareFixturAdmin__c.Name)を、ページ遷移なしで動的に渡す方法を知りたいです。
今回の学習範囲的に、Javascriptなどもできれば使わずに済むのであればうれしいです。
どなたかよろしくお願いします。

関連するカスタムオブジェクトとリレーション(備品セットは中間オブジェクト)
関連するカスタムオブジェクト

出力イメージ(特定の備品を静的に指定しているため、同じ備品の情報が出力されています)
出力イメージ

コード
・Visualforceページ viewSoftwareFixture.vfp
<apex:page standardController="SoftwareFixtureAdmin__c" extensions="getFixture,getPC">
    <apex:pageBlock >
    <apex:repeat value="{!fixtures}" var="fix" id="repeatFix">
        <apex:pageBlockSection title="{!fix.Name}" columns="1">
            <apex:pageBlockSection columns="3">
            <apex:outputField value="{!fix.ProductID__c}" rendered="{!fix.ProductID__c!=NULL}"/>
            <apex:outputField value="{!fix.ProductKey__c}" rendered="{!fix.ProductKey__c!=NULL}"/>
            <apex:outputField value="{!fix.UserID__c}" rendered="{!fix.UserID__c!=NULL}"/>
            <apex:outputField value="{!fix.LicenseLimit__c}" rendered="{!fix.LicenseLimit__c!=NULL}"/>
            <apex:outputField value="{!fix.Having__c}"/>
            <apex:outputField value="{!fix.Using__c}"/>
            <apex:outputField value="{!fix.CanUse__c}"/>
	        </apex:pageBlockSection>
		    <apex:repeat value="{!PCs}" var="pc" id="repeatPC">
		        <apex:pageBlockSection title="{!pc.Name}" columns="3">
		            <apex:outputField value="{!pc.User__c}"/>
		            <apex:outputField value="{!pc.Place__c}"/>
		            <apex:outputField value="{!pc.RentalDay__c}"/>
		        </apex:pageBlockSection>
		        </apex:repeat>
            </apex:pageBlockSection>
        </apex:repeat>
    </apex:pageBlock>
</apex:page>
・Apexクラス getFixture.apxc
public class getFixture {
    public List<SoftwareFixtureAdmin__c> fixtures{
        get;
        set;
    }
    
    public getFixture(ApexPages.StandardController controller){
        this.fixtures = [SELECT Name, ProductID__c, ProductKey__c, UserID__c, LicenseLimit__c, Having__c, Using__c, CanUse__c FROM SoftwareFixtureAdmin__c];
    }
}
・Apexクラス getPC.apxc
public class getPC {
    public List<PCAdmin__c> PCs{
        get;
        set;
    }
    
    public getPC(ApexPages.StandardController controller){
 		SoftwareFixtureAdmin__c fixId = [SELECT s.Id FROM SoftwareFixtureAdmin__c AS s WHERE Name =: Name]; //出力イメージはWHERE句を"WHERE Name = 'Microsoft Office 2013'と指定して出力
        this.PCs = [SELECT p.Name, p.User__c, p.Place__c, p.RentalDay__c FROM PCAdmin__c AS p WHERE p.Id IN(SELECT f.PC__c FROM FixtureSet__c AS f WHERE f.SoftwareFixtureAdmin__c =: fixId.Id) ORDER BY p.Name];
    }

    public String Name {
        get;
        set;
    }
}
Best Answer chosen by muromuro
Taiki YoshikawaTaiki Yoshikawa
Visualforceページ側とApexクラス側で値の受け渡しをしたいということでやりたいことはわかりました。人によって実装方法が異なるとは思いますのであくまで私の考えなのですが、まずクラス構成を下記のようにしてみてください。

- VFページ
- コントローラクラス
- コントローラクラスから呼び出すクラス (getFixtureとgetPCはこちら)

取引先検索画面を例とした実装イメージです。
<apex:page controller="AccountSearchController" showHeader="true" sidebar="true" id="page">
    <apex:form id="form">
        <apex:pageBlock id="block">
            <apex:pageMessages id="msg" />
            <apex:pageBlockButtons location="bottom">
                <apex:commandButton value=" {!$Label.Search} " title=" {!$Label.Search} " action="{!doSearch}" reRender="form" />
            </apex:pageBlockButtons>
            <apex:pageBlockSection columns="2" id="section">
                <apex:inputField value="{!account.Name}" required="false" />
                <apex:inputField value="{!account.AccountNumber}" required="false" />
            </apex:pageBlockSection>
        </apex:pageBlock>
        <apex:pageBlock id="resultBlock">
            <apex:pageBlockTable value="{!accounts}" var="item">
                <apex:column headerValue="{!$ObjectType.Account.Fields.Name.Label}">
                    <apex:outputField value="{!item.Name}" />
                </apex:column>
                <apex:column headerValue="{!$ObjectType.Account.Fields.AccountNumber.Label}">
                    <apex:outputField value="{!item.AccountNumber}" />
                </apex:column>
                <apex:column headerValue="{!$ObjectType.Account.Fields.Phone.Label}">
                    <apex:outputField value="{!item.Phone}" />
                </apex:column>
                <apex:column headerValue="{!$ObjectType.Account.Fields.Fax.Label}">
                    <apex:outputField value="{!item.Fax}" />
                </apex:column>
            </apex:pageBlockTable>
        </apex:pageBlock>
    </apex:form>
</apex:page>
public with sharing class AccountSearchController {

    private AccountSearchHelper helper = new AccountSearchHelper();
    private AccountSearchDao dao = new AccountSearchDao();

    public Account account {get; set;}
    public List<Account> accounts {get; set;}

    /**
     * コンストラクタ
     */
    public AccountSearchController() {
        try {
            this.account = new Account();
            this.accounts = new List<Account>();
        } catch(Exception e) {
            CommonUtil.msgException(e);
            return;
        }  
    }

    /**
     * 検索ボタン
     */
    public void doSearch() {
        try {
            // 取引先一覧取得
            this.accounts = this.dao.getAccounts(this.account);
            // リスト判定
            if (this.helper.isEmptyList(this.accounts.size(), System.Label.Not_Records)) return;
        } catch(Exception e) {
            CommonUtil.msgException(e);
            return;
        }  
    }
}

クラスのコンストラクタの部分は画面を表示したタイミングで必ず実行される処理となります。
doSearchのメソッドはapex:commandButtonから呼び出すときのサンプルです。

コンストラクタ内の処理ではページ遷移は実行できませんので、もし特定の条件で遷移する仕様の場合はコンストラクタではなくapex:pageタグでactionを指定して処理を実行してください。

下記の処理でコントローラクラスから別のクラスを呼び出しています。
private AccountSearchHelper helper = new AccountSearchHelper();
private AccountSearchDao dao = new AccountSearchDao();

クラス名は自由に付けることができるのでHelperやDaoである必要はありません。クラス内の処理も記載しておきます。
public with sharing class AccountSearchHelper {

    /**
     * コンストラクタ
     */
    public AccountSearchHelper() {
        
    }

    /**
     * リスト件数判定
     */
    public Boolean isEmptyList(Integer listSize, String message) {
        if (listSize == 0) {
            CommonUtil.msgWarning(message);
            return true;
        }

        return false;
    }
public with sharing class AccountSearchDao {

    /**
     * コンストラクタ
     */
    public AccountSearchDao() {
        
    }

    /**
     * 取引先一覧取得
     */
    public List<Account> getAccounts(Account account) {
        String query = '';
        query += ' SELECT ';
        query += '  Id ';
        query += ' ,Name ';
        query += ' ,AccountNumber ';
        query += ' ,Phone ';
        query += ' ,Fax ';
        query += ' FROM ';
        query += ' Account ';

        String joinQuery = ' WHERE ';
        // 取引名
        if (String.isNotEmpty(account.Name)) {
            query += joinQuery + 'Name LIKE ' + CommonUtil.toQuery(account.Name + '%');
            joinQuery = ' AND ';
        }
        // 取引先番号
        if (String.isNotEmpty(account.AccountNumber)) {
            query += joinQuery + 'AccountNumber = ' + CommonUtil.toQuery(account.AccountNumber);
            joinQuery = ' AND ';
        }

        query += ' ORDER BY Name ASC ';
        query += ' LIMIT 200 ';

        return database.query(query);
    }
}

システム管理者の権限でアクセス件が無いとエラーになっているのはおそらくクラスの宣言方法などに誤りがあるからだと思います。
ページから呼び出すのはコントローラクラスの一つだけにしてシンプルな形にしてみてください。




 

All Answers

Taiki YoshikawaTaiki Yoshikawa
ボタンを押したタイミングなどでしたらactionをつかって処理を行うことができます。引数渡しが必要な場合はapex:paramが使えます。
http://tyoshikawa1106.hatenablog.com/entry/2012/12/20/003123
muromuromuromuro
Taiki Yoshikawa様

ご教授ありがとうございます。
commandButtonとparamを以下のように試してみたのですが、アクセス権がありませんとエラーが出たため実行できませんでした(練習用の環境のため実質的な管理者です)。
<apex:page standardController="SoftwareFixtureAdmin__c" extensions="getFixture,getPC">
    <apex:pageBlock >
        <apex:form id="formId">
    <apex:repeat value="{!fixtures}" var="fix" id="repeatFix">
        <apex:pageBlockSection title="{!fix.Name}" columns="1">
  // 中略
            <apex:detail subject="{!fix.CanUse__c}" inlineEdit="true"/>
            <apex:commandButton value="test" action="{!doClick}" rerender="formId">
                <apex:param name="parameter" value="{!fix.Name}"/>
            </apex:commandButton>
	        </apex:pageBlockSection>
		    <apex:repeat value="{!PCs}" var="pc" id="repeatPC">
		        <apex:pageBlockSection title="{!pc.Name}" columns="3">
  // 中略
		        </apex:pageBlockSection>
		        </apex:repeat>
            </apex:pageBlockSection>
        </apex:repeat>
            </apex:form>
    </apex:pageBlock>
</apex:page>
public class getPC {

  // 中略

    public getPC(ApexPages.StandardController controller){
        if(String.isEmpty(Name)){
            Name = 'Microsoft Office 2013';
        }
        SoftwareFixtureAdmin__c fixId = [SELECT s.Id FROM SoftwareFixtureAdmin__c AS s WHERE Name =: Name];
        this.PCs = [SELECT p.Name, p.User__c, p.Place__c, p.RentalDay__c FROM PCAdmin__c AS p WHERE p.Id IN(SELECT f.PC__c FROM FixtureSet__c AS f WHERE f.SoftwareFixtureAdmin__c =: fixId.Id) ORDER BY p.Name];
    }

  // 中略
    
    public void doClick(){
        Name = System.currentPageReference().getParameters().get('parameter');
    }
}
また、可能であればアクセスと同時に表示できるようにしたいと考えています(Javascriptのonload()と同じタイミング)。よろしくお願いいたします。
Taiki YoshikawaTaiki Yoshikawa
Visualforceページ側とApexクラス側で値の受け渡しをしたいということでやりたいことはわかりました。人によって実装方法が異なるとは思いますのであくまで私の考えなのですが、まずクラス構成を下記のようにしてみてください。

- VFページ
- コントローラクラス
- コントローラクラスから呼び出すクラス (getFixtureとgetPCはこちら)

取引先検索画面を例とした実装イメージです。
<apex:page controller="AccountSearchController" showHeader="true" sidebar="true" id="page">
    <apex:form id="form">
        <apex:pageBlock id="block">
            <apex:pageMessages id="msg" />
            <apex:pageBlockButtons location="bottom">
                <apex:commandButton value=" {!$Label.Search} " title=" {!$Label.Search} " action="{!doSearch}" reRender="form" />
            </apex:pageBlockButtons>
            <apex:pageBlockSection columns="2" id="section">
                <apex:inputField value="{!account.Name}" required="false" />
                <apex:inputField value="{!account.AccountNumber}" required="false" />
            </apex:pageBlockSection>
        </apex:pageBlock>
        <apex:pageBlock id="resultBlock">
            <apex:pageBlockTable value="{!accounts}" var="item">
                <apex:column headerValue="{!$ObjectType.Account.Fields.Name.Label}">
                    <apex:outputField value="{!item.Name}" />
                </apex:column>
                <apex:column headerValue="{!$ObjectType.Account.Fields.AccountNumber.Label}">
                    <apex:outputField value="{!item.AccountNumber}" />
                </apex:column>
                <apex:column headerValue="{!$ObjectType.Account.Fields.Phone.Label}">
                    <apex:outputField value="{!item.Phone}" />
                </apex:column>
                <apex:column headerValue="{!$ObjectType.Account.Fields.Fax.Label}">
                    <apex:outputField value="{!item.Fax}" />
                </apex:column>
            </apex:pageBlockTable>
        </apex:pageBlock>
    </apex:form>
</apex:page>
public with sharing class AccountSearchController {

    private AccountSearchHelper helper = new AccountSearchHelper();
    private AccountSearchDao dao = new AccountSearchDao();

    public Account account {get; set;}
    public List<Account> accounts {get; set;}

    /**
     * コンストラクタ
     */
    public AccountSearchController() {
        try {
            this.account = new Account();
            this.accounts = new List<Account>();
        } catch(Exception e) {
            CommonUtil.msgException(e);
            return;
        }  
    }

    /**
     * 検索ボタン
     */
    public void doSearch() {
        try {
            // 取引先一覧取得
            this.accounts = this.dao.getAccounts(this.account);
            // リスト判定
            if (this.helper.isEmptyList(this.accounts.size(), System.Label.Not_Records)) return;
        } catch(Exception e) {
            CommonUtil.msgException(e);
            return;
        }  
    }
}

クラスのコンストラクタの部分は画面を表示したタイミングで必ず実行される処理となります。
doSearchのメソッドはapex:commandButtonから呼び出すときのサンプルです。

コンストラクタ内の処理ではページ遷移は実行できませんので、もし特定の条件で遷移する仕様の場合はコンストラクタではなくapex:pageタグでactionを指定して処理を実行してください。

下記の処理でコントローラクラスから別のクラスを呼び出しています。
private AccountSearchHelper helper = new AccountSearchHelper();
private AccountSearchDao dao = new AccountSearchDao();

クラス名は自由に付けることができるのでHelperやDaoである必要はありません。クラス内の処理も記載しておきます。
public with sharing class AccountSearchHelper {

    /**
     * コンストラクタ
     */
    public AccountSearchHelper() {
        
    }

    /**
     * リスト件数判定
     */
    public Boolean isEmptyList(Integer listSize, String message) {
        if (listSize == 0) {
            CommonUtil.msgWarning(message);
            return true;
        }

        return false;
    }
public with sharing class AccountSearchDao {

    /**
     * コンストラクタ
     */
    public AccountSearchDao() {
        
    }

    /**
     * 取引先一覧取得
     */
    public List<Account> getAccounts(Account account) {
        String query = '';
        query += ' SELECT ';
        query += '  Id ';
        query += ' ,Name ';
        query += ' ,AccountNumber ';
        query += ' ,Phone ';
        query += ' ,Fax ';
        query += ' FROM ';
        query += ' Account ';

        String joinQuery = ' WHERE ';
        // 取引名
        if (String.isNotEmpty(account.Name)) {
            query += joinQuery + 'Name LIKE ' + CommonUtil.toQuery(account.Name + '%');
            joinQuery = ' AND ';
        }
        // 取引先番号
        if (String.isNotEmpty(account.AccountNumber)) {
            query += joinQuery + 'AccountNumber = ' + CommonUtil.toQuery(account.AccountNumber);
            joinQuery = ' AND ';
        }

        query += ' ORDER BY Name ASC ';
        query += ' LIMIT 200 ';

        return database.query(query);
    }
}

システム管理者の権限でアクセス件が無いとエラーになっているのはおそらくクラスの宣言方法などに誤りがあるからだと思います。
ページから呼び出すのはコントローラクラスの一つだけにしてシンプルな形にしてみてください。




 
This was selected as the best answer
muromuromuromuro
Taiki Yoshikawa様
ありがとうございます。
提示していただいた取引先の例を実行しようとしたのですが、いくらかエラーが出てしまい保存できない状況です。これはどのようにすれば直りますでしょうか。User-added image
Taiki YoshikawaTaiki Yoshikawa
コメントアウトして頂いて...と思ったのですが思ったより差し込んでいたみたいです。こちらを入れていただければ大丈夫です。
public with sharing class CommonUtil {

    /**
     * URLパラメータ取得
     */
    public static String getParameters(String prmValue) {
        
        String parameter = System.currentPageReference().getParameters().get(prmValue);
        
        if (String.isEmpty(parameter)) {
            return '';
        }
        return parameter;
    }
    
    /**
     * 前画面URL存在判定
     */
    public static PageReference isReturnUrl(String prmRetUrl) {
        
        if(String.isEmpty(prmRetUrl)) {
            return new PageReference('/home/home.jsp');
        }
        
        return new PageReference(prmRetUrl);
    }
    
    /**
     * 前画面遷移
     */
    public static PageReference getReturnUrl() {
        String retUrl = CommonUtil.getParameters(CommonConst.PARAM_RETURN_URL);
        return CommonUtil.isReturnUrl(retUrl);
    }
    
    /**
     * 正常系メッセージ表示
     */
    public static void msgInfo(String prmMsg) {
        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO, prmMsg));
    }
    
    /**
     * 異常系メッセージ表示
     */
    public static void msgError(String prmMsg) {
        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, prmMsg));
    }
    
    /**
     * 警告系メッセージ表示
     */
    public static void msgWarning(String prmMsg) {
        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.WARNING, prmMsg));
    }
    
    /**
     * DmlExceptionメッセージ表示
     */
    public static void msgDmlError(Exception e) {
        ApexPages.addMessages(e);
    }
    
    /**
     * Exceptionメッセージ表示
     */
    public static void msgException(Exception e) {
        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, System.Label.System_Error_Message));
        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL,e.getMessage()));
        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL,
            'Line:' + String.valueOf(e.getLineNumber()) + '【' + e.getTypeName() + '】'));
    }
    
    /**
     * Exceptionメッセージを取得
     */
    public static String getExceptionMsg(Exception e, String prmMsg) {
        return prmMsg + '\n' + e.getMessage() + '\n' + 'Line:' + String.valueOf(e.getLineNumber());
    }
    
    /**
     * SingleQuote追加
     */
    public static String toQuery(String prmValue) {
        
        if(String.isEmpty(prmValue)) {
            // 値なし
            return '\'' + '\'';
        }
        // 値あり
        return '\'' + String.escapeSingleQuotes(prmValue) + '\'';
    }
}

『CommonConst.PARAM_RETURN_URL』の中身は 文字列の 'retURL' です。
『System.Label.System_Error_Message』の中身は文字列の 'システムエラー' です。

ひとまずこれで保存できると思います。
よろしくお願いいたします。
 
muromuromuromuro
Taiki Yoshikawa様
ありがとうございます。
動作が確認できましたので、これを参考にして書いていきたいと思います。
muromuromuromuro
Taiki Yoshikawa様
昨日、先輩と再度この件について協議した結果、以下のような形に落ち着きましたので、ご報告いたします。
SOQLで主従関係をV字に辿れるということが分かったので、それを採用しました。
(デザインはその後のフィードバックにより多少変更しております)
この度はわざわざ時間を割いていただきありがとうございました。
またご縁がありましたら、よろしくお願いいたします。

viewSoftwareFixture.vfp
<apex:page standardController="SoftwareFixtureAdmin__c" extensions="getFixture">
   	<apex:form id="formId">
        <apex:variable var="col" value="0"/>
	    <apex:repeat value="{!fixtures}" var="fix" id="repeatFix">
            <apex:variable var="col" value="{!(VALUE(col)+1)}"/>
    		<apex:pageBlock tabStyle="{!IF(MOD(VALUE(col),2)==0, 'PCAdmin__c', 'SoftwareFixtureAdmin__c')}">
		        <apex:pageBlockSection title="{!fix.Name}" columns="1">
			        <apex:pageBlockSection columns="3">
	            		<apex:outputField value="{!fix.ProductID__c}" rendered="{!fix.ProductID__c!=NULL}"/>
	            		<apex:outputField value="{!fix.ProductKey__c}" rendered="{!fix.ProductKey__c!=NULL}"/>
	            		<apex:outputField value="{!fix.UserID__c}" rendered="{!fix.UserID__c!=NULL}"/>
	            		<apex:outputField value="{!fix.LicenseLimit__c}" rendered="{!fix.LicenseLimit__c!=NULL}"/>
	            		<apex:outputField value="{!fix.Having__c}"/>
	            		<apex:outputField value="{!fix.Using__c}"/>
	            		<apex:outputField value="{!fix.CanUse__c}"/>
	                </apex:pageBlockSection>
                        <apex:repeat value="{!fix.Fixture1__r}" var="fixSet">
                            <apex:pageBlockSection title="{!fixSet.PC__r.Name}" columns="3">
	            				<apex:outputField value="{!fixSet.PC__r.User__c}"/>
	            				<apex:outputField value="{!fixSet.PC__r.Place__c}"/>
	            				<apex:outputField value="{!fixSet.PC__r.RentalDay__c}"/>
                            </apex:pageBlockSection>
                        </apex:repeat>
                </apex:pageBlockSection>
    		</apex:pageBlock>
        </apex:repeat>
    </apex:form>
</apex:page>

getFixture.apxc
public class getFixture {
    public List<SoftwareFixtureAdmin__c> fixtures{
        get;
        set;
    }
    public List<PCAdmin__c> PCs{get; set;}
    public Integer col {get; set;}
    
    public getFixture(ApexPages.StandardController controller){
        this.fixtures = [SELECT Id, Name, ProductID__c, ProductKey__c, UserID__c, LicenseLimit__c, Having__c, Using__c, CanUse__c, (SELECT PC__c, PC__r.Name, PC__r.User__c, PC__r.Place__c, PC__r.RentalDay__c FROM Fixture1__r ORDER BY PC__r.Name) FROM SoftwareFixtureAdmin__c];
    }
}

getPC.apxc→廃止