Upload
salesforce-developers-japan
View
2.383
Download
3
Embed Size (px)
DESCRIPTION
Visualforceはカスタムユーザ・インタフェースを作成するのに欠かせないパワフルなツールですが、この大いなる力には、大いなる責任が伴います。作成したページが引き締まって快速に動作することは、良いユーザ体験や導入・定着化には非常に重要です。このWebinarでは、いくつかの上級者向けのVisualforce機能にトピックを置いて、作成するページの効率化を支援します。すでにVisualforceフレームワークを利用している開発者向けのセッションです。
Citation preview
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
Force.com Webinar:アドバンスド Visualforce
Mitsuhiro OkamotoProgram Manager
Developer / Platform Marketing
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
Agenda
1. 前提条件2. 厄介だけどいい友達: View State
3. View Stateの管理4. 非同期Apex
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
この アドバンスド Webinar の前提条件...
...不明点なく、自信を持ってVisualforceが記述できる
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
この アドバンスド Webinar の前提条件...
...不明点なく、自信を持ってVisualforceが記述できる
...一般的なApexコードを書く事ができる
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
この アドバンスド Webinar の前提条件...
...不明点なく、自信を持ってVisualforceが記述できる
...一般的なApexコードを書く事ができる
...HTML & JavaScriptそしてAJAXのコンセプトを理解している
Q: View Stateとは?
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
A: Apexコントローラの状態やVisualforceページの状態をサーバリクエスト間も保持するための、Visualforceページ内に暗号化されたhiddenの <input> フィールドのこと。 このフィールドは
<apex:form> タグがページ上にある場合のみ生成される。
Visualforceのライフサイクル
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
<input type="hidden" value="..."/>
HTTP POST
HTTP GET
A
B
C
D
E
A : URLがリクエストされるB : Apexコントローラがサーバ上でインスタンス化されるC : コントローラの状態がView Stateに直列化(シリアライズ)& 暗号化されてD : ページマークアップがブラウザに送信され、描画されるE : View Stateが復号 & 復元される(PostBack時)
View State: 利点と課題
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
課題 :-(
• 巨大化し、パフォーマンスに影響を与える可能性
• サイズ制限(135k)を持っている
• 複雑なAJAX機能に対応しづらい
すばらしい点 :-)
• 自動的にフィールドの値を保持してくれる
• 簡単なAJAX機能を持ち合わせている
• 非常に簡単に使えるre-renderページコンポーネントを持つ
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
View Stateを必要とするもの...
<apex:action*><apex:command*><apex:inlineEditSupport><apex:input*><apex:select*>
どのようにView Stateを管理するか?
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
A. コンポーネントの数を減らす
どのようにView Stateを管理するか?
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
A. コンポーネントの数を減らす
B. transient キーワードを利用する
どのようにView Stateを管理するか?
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
A. コンポーネントの数を減らす
B. transient キーワードを利用する
C. JavaScript Remotingを利用する
どのようにView Stateを管理するか?
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
A. コンポーネントの数を減らす
B. transient キーワードを利用する
C. JavaScript Remotingを利用するD. Streaming APIを利用する
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション A: コンポーネント数を減らす
<apex:outputPanel layout="inline"...>
<apex:outputPanel layout="block"...>
<apex:panelGrid...>
<apex:outputLink...>
<apex:outputText styleClass="..."...>
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション A: コンポーネント数を減らす
<apex:outputPanel layout="inline"...>
<apex:outputPanel layout="block"...>
<apex:panelGrid...>
<apex:outputLink...>
<apex:outputText styleClass="..."...>
<span...>
<div...>
<table...>
<a...>
<span...>
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション A: コンポーネント数を減らす
<span...>
<div...>
<table...>
<a...>
<span...>
オプション B: transient キーワード
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
public with sharing class EditClientController {
public Contact client { get; set; } transient public List<Contact> connections { get; set; } transient public List<Account> previousEmployers { get; set; } transient public Set<String> hashTags { get; set; }
...
}
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション B: transient キーワードを使う
BEF
OR
EA
FTER
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション B: transient キーワードを使う
57%
BEF
OR
EA
FTER
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション C: JavaScript Remotingを使うQ: JavaScript Remotingとは?
A: ステートレスにApexコントローラ内のメソッドをJavascriptから呼ぶ方法
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション C: Use JavaScript Remoting
取引先責任者を検索:
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション C: Use JavaScript Remoting
取引先責任者を検索:
<apex:actionFunction ... /><apex:actionRegion ... /><apex:actionSupport ... />
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション C: Use JavaScript Remoting
取引先責任者を検索:
JavaScript Remoting
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
JavaScript Remoting のライフサイクル
JS Function
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
JavaScript Remoting のライフサイクル
JS Function
Apex Method
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
JavaScript Remoting のライフサイクル
JS Function
Apex Method
JS Callback
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
JavaScript Remoting のライフサイクル
JS Function
Apex Method
JS Callback
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
JavaScript Remoting のライフサイクル
JS Function
Apex Method
JS Callbackクライアントサイド
サーバサイド
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
JS Function
Apex Method
JS Callback
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション C: JavaScript Remoting: ページ
<apex:page controller="FindCustomerController">
<input id="searchField" type="text" placeholder="姓を入力"/> <button onclick="handleButtonClick();">検索</button> <table> <tbody id="results"></tbody> </table>
</apex:page>
JS Function
Apex Method
JS Callback
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション C: JavaScript Remoting: ページ
<apex:page controller="FindCustomerController">
<input id="searchField" type="text" placeholder="姓を入力"/> <button onclick="handleButtonClick();">検索</button> <table> <tbody id="results"></tbody> </table>
</apex:page>
JS Function
Apex Method
JS Callback
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション C: JavaScript Remoting: ページ
<apex:page controller="FindCustomerController">
<input id="searchField" type="text" placeholder="姓を入力"/> <button onclick="handleButtonClick();">検索</button> <table> <tbody id="results"></tbody> </table>
</apex:page>
JS Function
Apex Method
JS Callback
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション C: JavaScript Remoting: JavaScript
function handleButtonClick() { var searchTerm = document.getElementById("searchField").value; FindCustomerController.doSearch(searchTerm, renderResults);}
JS Function
Apex Method
JS Callback
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション C: JavaScript Remoting: JavaScript
function handleButtonClick() { var searchTerm = document.getElementById("searchField").value; FindCustomerController.doSearch(searchTerm, renderResults);}
JS Function
Apex Method
JS Callback
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション C: JavaScript Remoting: JavaScript
function handleButtonClick() { var searchTerm = document.getElementById("searchField").value; FindCustomerController.doSearch(searchTerm, renderResults);}
JSコールバック関数ApexメソッドパラメータApexクラス Apexメソッド
JS Function
Apex Method
JS Callback
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション C: JavaScript Remoting: Apexクラスpublic with sharing class FindCustomerController {
@RemoteAction public static List<Contact> doSearch(String customerLastName) { customerLastName = '%' + customerLastName + '%'; return [ SELECT id, FirstName, LastName FROM Contact WHERE LastName LIKE :customerLastName LIMIT 200 ]; }
}
JS Function
Apex Method
JS Callback
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション C: JavaScript Remoting: Apexクラスpublic with sharing class FindCustomerController {
@RemoteAction public static List<Contact> doSearch(String customerLastName) { customerLastName = '%' + customerLastName + '%'; return [ SELECT id, FirstName, LastName FROM Contact WHERE LastName LIKE :customerLastName LIMIT 200 ]; }
}
JS Function
Apex Method
JS Callback
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション C: JavaScript Remoting: コールバック
function renderResults(results, event) { var container = document.getElementById("results"), html = []; for (var i=0, j=results.length; i<j; i++) { html.push("<tr><td>"); html.push(results[i].LastName + ", " + results[i].FirstName); html.push("</td></tr>"); } container.innerHTML = html.join("");}
JS Function
Apex Method
JS Callback
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション C: JavaScript Remoting: 結果
JS Function
Apex Method
JS Callback
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション C: JavaScript Remoting: 結果
440ms 215msBEFORE AFTER
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション C: JavaScript Remoting: 結果
440ms 215ms52%
BEFORE AFTER
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション D: Streaming APIを使うQ: Streaming APIとは?
A: Salesforceインスタンスからポーリングをせずにほぼリアルタイムに更新を効率よく取得する方法
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション D: Streaming APIを使う
<apex:page controller="NewAccountsController"><apex:form>
<apex:actionPoller action="{!find}" rerender="wrapper" interval="15"/> <h1>Streaming API サンプル</h1> <h2>新規取引先</h2> <apex:outputPanel id="wrapper"></apex:outputPanel>
</apex:form></apex:page>
BEFORE
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション D: Streaming APIを使う
<apex:page controller="NewAccountsController">
<apex:includeScript value="..."/> <!-- 4つの js ファイルを読み込み -->
<h1>Streaming API サンプル</h1> <h2>新規取引先</h2> <div id="wrapper"></div> <script>... $.cometd.init(...) $.cometd.subscribe(...) ...</script>
</apex:page>
AFTER
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
オプション D: Streaming APIを使う: 手順SOQLクエリを定義するPushTopicレコードを定義するVisualforceページに必要なJavascriptをインクルードするcometdのinit(...)およびsubscribe(...)を呼び出す (Inline JS)
何が起きるかを見る
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
非同期 Apexpublic with sharing class SendInvoiceController{
@RemoteAction public static String requestAllInvoices(String customerId) { sendAllInvoices(customerId); return('All invoices have been requested.'); }
@future private static void sendAllInvoices(String customerId) { EmailHelper.emailCustomerInvoices(customerId); }
}
Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp
Q & A
Mitsuhiro OkamotoProgram Manager
Developer / Platform Marketing