[Salesforce] Lightning Components force: タグを試してみた

By |12月 21, 2015|salesforce, |


はじめまして。エンジニアの川畑です。
Lightning Component の開発は、メンバーと日々模索しているような状況なのですが、ふとリファレンスを見ていたら force:〜 があることに今さら気付きました。(どうやら1年前からあったみたいです…)

若干挙動が怪しい部分もありますが、ほとんど Visualforce と同じように使えるので知っていて損はなさそうです。

  • Visualforce の同名タグとほぼ一緒
  • Salesforce1 もしくは Lightning アプリケーションビルダーで使える(aura:application では使わないほうが良い)
  • パッケージングも可能

以下検証コードとコメントです。

force:recordView

Salesforce1

– ほぼイメージ通り。
– ページレイアウトの変更も反映されます。
– トランスレーションワークベンチも問題なく動作するようです。
– ただしリンク(アクション)は Salesforce1 の Lightning タブ もしくは Lightning アプリケーションでなければ動作しないです。

コードはこれだけです。
Component
[html]
<aura:component controller="elfL1" implements="flexipage:availableForAllPageTypes,force:appHostable">
<aura:handler name="init" value="{!this}" action="{!c.init}"></aura:handler>
<aura:attribute name="Battle_Station" type="isvdev__Battle_Station__c" default="{ ‘sobjectType’: ‘isvdev__Battle_Station__c’ }"></aura:attribute>
<force:recordview recordId="{!v.Battle_Station.Id}" type="FULL"></force:recordview>
</aura:component>
[/html]
Controller
[html]
({
init : function(component, event, helper) {
var action = component.get("c.getBattleStation");
action.setCallback(this, function(response) {
component.set("v.Battle_Station", response.getReturnValue());
});
$A.enqueueAction(action);
}
})
[/html]

Visualforce と同様に編集するときはforce:recordEditを使います。

Salesforce1

– force:recordDetail と同様です。
– 2回目以降の保存で排他エラーが出るのですが解決できませんでした…
“This record was modified by Takahiro Kawabata during your edit session. Make a note of the data you entered, then reload the record and enter your updates again.”

コードは以下。
Component
[html]
<aura:component controller="elfL1" implements="flexipage:availableForAllPageTypes,force:appHostable">
<aura:handler name="init" value="{!this}" action="{!c.init}"/>
<aura:attribute name="Battle_Station" type="isvdev__Battle_Station__c" default="{ ‘sobjectType’: ‘isvdev__Battle_Station__c’ }"/>
<force:recordEdit aura:id="edit" recordId="{!v.Battle_Station.Id}"/>
<ui:button label="Save" press="{!c.save}"/>
</aura:component>
[/html]
Controller
[html]
({
init : function(component, event, helper) {
var action = component.get("c.getBattleStation");
action.setCallback(this, function(response) {
component.set("v.Battle_Station", response.getReturnValue());
});
$A.enqueueAction(action);
},
save : function(component, event, helper) {
component.find("edit").get("e.recordSave").fire();
}
})
[/html]

すこし期待外れだった force:inputField

Salesforce1

– 項目のラベルが表示されなかった(仕様? Visualforce は表示されてたと記憶)
– 項目のアクセス権がないと An internal server error has occurred.
– aura:application の中で使うとなんとも残念なレイアウトになってしまい、選択リストを動作させるのにもワークアラウンドが必要でした。
salesforce1 app – Lightning – How to use force:inputField? – Salesforce Stack Exchange

Aura

コード。
Component
[html]
<aura:component controller="elfL1" implements="flexipage:availableForAllPageTypes,force:appHostable">
<ltng:require scripts="/resource/jquery"/>
<aura:handler name="init" value="{!this}" action="{!c.init}"/>
<aura:attribute name="Battle_Station" type="isvdev__Battle_Station__c" default="{ ‘sobjectType’: ‘isvdev__Battle_Station__c’ }"/>
<form>
<force:inputField aura:id="Name" value="{!v.Battle_Station.Name}" class="form-control uiInput–input input"/>
<force:inputField aura:id="Project_Status" value="{!v.Battle_Station.isvdev__Project_Status__c}" class="elfForceEditable"/>
<ui:button class="form-control" aura:id="button" label="Save" press="{!c.save}"/>
</form>
</aura:component>
[/html]
Controller
[html]
({
init : function(component, event, helper) {
debugger;
var action = component.get("c.getBattleStation");
action.setCallback(this, function(response) {
component.set("v.Battle_Station", response.getReturnValue());
//workaround
$(‘select.elfForceEditable’).removeAttr(‘disabled’);
});
$A.enqueueAction(action);
},
save : function(component, event, helper) {
var action = component.get("c.saveBattleStation");
var battleStation = component.get("v.Battle_Station");
action.setParams({"battleStation": battleStation});
action.setCallback(this, function() { console.log(‘SAVED.’); } );
$A.enqueueAction(action);
},
})
[/html]

force:outputField は force:inputField とほぼ同様なので省略。

一番部品っぽいforceChatter:feed

Battle_Station_レコードページ_-_Lightning_アプリケーションビルダー

– ページレイアウト(ベータ)でも動きました。

Component
[html]
<aura:component implements="flexipage:availableForAllPageTypes,force:appHostable">
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
<aura:attribute name="type" type="String" default="News" description="The type of feed" access="GLOBAL"/>
<aura:attribute name="types" type="String[]"
default="Bookmarks,Company,Files,Groups,Home,News,People"
description="A list of feed types"/>
<h1>My Feeds</h1>
<ui:inputSelect aura:id="typeSelect" change="{!c.onChangeType}" label="Type"/>
<div aura:id="feedContainer" class="feed-container">
<forceChatter:feed />
</div>
</aura:component>
[/html]
Controller
[html]
({
// Handle component initialization
doInit : function(component, event, helper) {
var type = component.get("v.type");
var types = component.get("v.types");
var typeOpts = new Array();

// Set the feed types on the ui:inputSelect component
for (var i = 0; i < types.length; i++) {
typeOpts.push({label: types[i], value: types[i], selected: types[i] === type});
}
component.find("typeSelect").set("v.options", typeOpts);
},

onChangeType : function(component, event, helper) {
var typeSelect = component.find("typeSelect");
var type = typeSelect.get("v.value");
component.set("v.type", type);

// Dynamically create the feed with the specified type
$A.createComponent(
"forceChatter:feed",
{ "type": type },
function(feed){
var feedContainer = component.find("feedContainer");
feedContainer.set("v.body", feed);
}
);
}
})
[/html]

※こちらは手持ちが無く今回は未検証です force:canvasApp

最後に

今回のタグはいずれも Visualforce 経験者にとって理解しやすいのではと思いますがいかがでしょうか。
自分はまだまだページアプリケーションの考え方から脱却できてないのですが、これからはコンポーネントの組み合わせによるアプリケーション開発手法を模索していきたいと思います。(個人的にはパーツを組み立ててミニ四駆を作るようなイメージです!)

10087273a