Transcript

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

想定と難易度

Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp

この アドバンスド Webinar の前提条件...

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のコンセプトを理解している

Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp

厄介だけどいい友達:View State

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*>

Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp

View Stateの管理

どのようにView Stateを管理するか?

Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp

どのように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: コンポーネント数を減らす

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 のライフサイクル

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

非同期 Apex

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

Join the conversation: #forcewebinarハッシュタグでShareしよう: #forcewebinarjp

Thank you