今日はちょっと、内容多めです。
VisualForceのタグの中で、actionXXというタグがいくつかありますが、ちょっと多くてどれがどういう機能かが分からなくなりますね。
それぞれどういう機能なのかこのページで整理しました。
apex:actionタグたち
VisualForceタグの中でactionXXとついているタグは以下の5つです。
- apex:actionPoller
- apex:actionFunction
- apex:actionSupport
- apex:actionStatus
- apex:actionRegion
それぞれ役割が違いますが、共通して言えることは、AJAX要求をする時に使用されるコンポーネントになります。
VisualForceにおけるAJAX要求とは何かというと、ボタンを押した時や時間経過などのイベントによって、
画面全体ではなく、一部のコンポーネントが更新されるような動作となります。
それぞれの解説
それぞれ、どういう動きをするか、実際にコードを書いて動きを確かめてみました。
それぞれ、VisualForceとApexを使用しますが、Apexは面倒だったので共通のものを使用しています。
まずはApexクラスから。
ActionMoverController.cls
public class ActionMoverController {
// ページを開いてからの秒数
public Integer timer{get; private set;}
// 更新対象レコード
public Account acc{get; set;}
// ページを開いた日時
private Datetime startTime;
public ActionMoverController(){
// 開始時間を記録
startTime = Datetime.now();
timer = 0;
}
// 初期処理
public void init(){
acc = [Select Id, Name, Industry From Account Limit 1];
}
// ページを開いた時間からの秒数を算出するアクション
public void timeConuter(){
Long mSec = Datetime.now().getTime() - startTime.getTime();
timer = (Integer)(mSec / 1000);
}
}
apex:actionPoller
apex:actionPollerタグは、時間経過によりイベントを起こす仕組みとなります。
VisualForceページで5秒間隔でイベントを起こすようにします。
仕組みとしては、intervalで指定した秒数毎にactionが起動され、reRenderで指定したコンポーネントのみを更新するという動きになっています。
ActionPollerMover.page
<apex:page controller="ActionMoverController">
<apex:form>
<apex:outputText value="{!timer}秒経過" id="counter"/>
<apex:actionPoller action="{!timeConuter}" reRender="counter" interval="5"/>
</apex:form>
</apex:page>
ページを開いた直後はこのような状態。
何もしないで5秒待つと秒数が切り替わります。
ユーザ側で何か操作することはなく、時間経過でイベントが走るので、
非同期のジョブを実行させている時の監視手段として使うことができます。
apex:actionFunction
apex:actionFunctionタグは、JavaScriptからApexコントローラーのアクションを呼び出すための手段として用いられます。
サーバ処理を実施する前に、クライアントサイド(主にJavaScript内)で必要な処理を実施してから呼び出すことができます。
ボタンを押したら秒数が更新されるようにします。
仕組みとしてはボタンを押した後、onclickによってJavaScriptが実行され、JavaScript内でactionFunctionで定義したメソッド(name)を呼び出し、コントローラのアクションを実行して、rerenderで指定したコンポーネントを更新するという感じです。
ActionFunctionMover.page
<apex:page controller="ActionMoverController">
<script type="text/javascript">
function timeCounterJS() {
// actionFunctionで定義したメソッド名からApexコントローラのアクションを呼び出す
getTime();
return false;
}
</script>
<apex:form >
<apex:outputText value="{!timer}秒経過" id="counter"/>
<apex:commandButton value="ボタンを押すと秒数表示" onclick="return timeCounterJS();" />
<apex:actionFunction name="getTime" action="{!timeConuter}" rerender="counter" />
</apex:form>
</apex:page>
ボタンを押す前の状態。
ボタンを押したら、押した時点での秒数が更新されます。
最終的にはJavaScript経由でApexコントローラのメソッドを呼び出すことになるので、イベント受信後にクライアント側で処理を実施する必要がある場合に使用されます。
apex:actionSupport
apex:actionSupportタグはVisualForceとのコンポーネントとのセットで使用され、コンポーネント側で起こったイベント(onclickやonchangeなど)を受けて、アクションを実施します。
今後はボタンではなくテキスト「ここを押すと秒数が更新されるよ」にクリックをするとイベントが走るようにします。
ActionSupportMover.page
<apex:page controller="ActionMoverController">
<apex:form >
<apex:outputText value="{!timer}秒経過" id="counter"/>
<apex:outputpanel id="msg" layout="block">
<apex:outputText value="ここを押すと秒数が更新されるよ" />
<apex:actionSupport event="onclick" action="{!timeConuter}" rerender="counter" />
</apex:outputpanel>
</apex:form>
</apex:page>
開始前。
テキストの部分をクリックすると秒数が更新。
コンポーネント毎にイベントを拾うことができるので、一部コンポーネントで特別な処理を実施したい場合に使用します。
apex:actionStatus
apex:actionStatusは単独で使用されることはありません。
上記タグとセットで使用され、サーバ側で処理中の際にアクションの進捗状態を表示するものになります。
apex:actionSupportで使用したイベントを流用して、apex:actionStatusタグを追加します。
もちろん、進捗状態を更新するために、apex:actionSupport側にstatus=”counterStatus”を入れるのを忘れないように。
ActionStatusMover.page
<apex:page controller="ActionMoverController">
<apex:form >
<apex:outputText value="{!timer}秒経過" id="counter"/>
<apex:outputpanel id="msg" layout="block">
<apex:outputText value="ここを押すと秒数が更新されるよ" />
<apex:actionSupport event="onclick" action="{!timeConuter}" rerender="counter" status="counterStatus"/>
</apex:outputpanel>
<apex:actionStatus id="counterStatus" startText="カウント中・・・" stopText=""/>
</apex:form>
</apex:page>
開始前の状態。
テキスト部分をクリック(キャプチャを取るタイミングがシビアだったのでちょっとインチキしました。。。)
サーバ処理が終わると、ステータスのところにはstopTextが表示(今回はstopTextがブランクなので、進捗が消える)。
AJAX要求でサーバ側の処理に時間がかかる場合に、ユーザ側へ進捗を知らせる手段として使用されます。
apex:actionRegion
apex:actionRegionはちょっと毛色が違います。
Apexコントローラ側でアクションを実施する場合、通常は入力可能なコンポーネント全部をサーバ側に送信しますが、apex:actionRegionを指定することによって、その中で括られたコンポーネントのみがサーバ側へ渡すことができます。
まずは、actionRegionを使用しないとどうなるでしょうか。
業種を切り替えた時に、テキストに更新されるように作ります。
ActionRegionMover.page(actionRegion未使用)
<apex:page controller="ActionMoverController" action="{!init}">
<apex:form >
<apex:pageBlock >
<apex:inputField value="{!acc.Name}" required="true" label="取引先名" />
<!-- <apex:actionRegion > -->
<apex:inputField value="{!acc.Industry}">
<apex:actionSupport event="onchange" rerender="industry"/>
</apex:inputField>
<apex:outputText id="industry" value="この会社の業種は{!acc.Industry}です" />
<!-- </apex:actionRegion> -->
</apex:pageBlock>
</apex:form>
</apex:page>
開始前の状態はこう。
業種を更新すると、テキストの方にも反映されます。
一見、動作上問題なさそうですが、必須項目が絡むとうまく更新されなくなります。
会社名をブランクにした状態で業種を変更すると。
業種が更新されなくなります。
Nameは必須項目なので、入力がない状態でアクションを実行しようとすると、アクション実施前のシステムチェックでNGとなって、Apexコントローラまで到達しないんですね。
では、ここでコメントアウトしていたapex:actionRegionを解放させましょう。
ActionRegionMover.page(actionRegion使用)
<apex:page controller="ActionMoverController" action="{!init}">
<apex:form >
<apex:pageBlock >
<apex:inputField value="{!acc.Name}" required="true" label="取引先名" />
<apex:actionRegion >
<apex:inputField value="{!acc.Industry}">
<apex:actionSupport event="onchange" rerender="industry"/>
</apex:inputField>
<apex:outputText id="industry" value="この会社の業種は{!acc.Industry}です" />
</apex:actionRegion>
</apex:pageBlock>
</apex:form>
</apex:page>
このように、取引先名に入力がなくても。
業種変更で見事に更新されます。
apex:actionRegionをつける事によって、業種だけサーバ側に送られる仕組みとなります。
上記例にあった通り、必須項目があるとサーバ側のアクションが実施できないことがあるため、
必須項目を必要としない時にサーバ処理を実施したいときに有効です。
まとめ
今日は内容多めでしたね。
それぞれのactionタグについての使い方、使い道をまとめると以下のようになります。
動作確認などで色々書きましたが、下の表を押さえておけばテスト対策にはなると思います。
| apex:actionPoller |
|
|---|---|
| apex:actionFunction |
|
| apex:actionSupport |
|
| apex:actionStatus |
|
| apex:actionRegion |
|


コメント