Skip to content

Instantly share code, notes, and snippets.

@peterknolle
Last active February 19, 2022 22:10
Show Gist options
  • Save peterknolle/3dc77c1a503996955e32 to your computer and use it in GitHub Desktop.
Save peterknolle/3dc77c1a503996955e32 to your computer and use it in GitHub Desktop.
<apex:page controller="jTableAccountsController">
<link href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/redmond/jquery-ui.css" rel="stylesheet" type="text/css" />
<link href="{!URLFOR($Resource.jtable, 'jtable/themes/jqueryui/jtable_jqueryui.min.css')}" rel="stylesheet" type="text/css" />
<apex:includeScript value="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"/>
<apex:includeScript value="https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"/>
<apex:includeScript value="{!URLFOR($Resource.jtable, 'jtable/jquery.jtable.min.js')}"/>
<apex:remoteObjects >
<apex:remoteObjectModel jsShortHand="acct" name="Account" fields="Id,Name,Phone,Fax"
retrieve="{!$RemoteAction.jTableAccountsController.retrieveAccts}"/>
<apex:remoteObjectModel jsShortHand="opp" name="Opportunity" fields="Id,Name,AccountId,StageName,Probability,Amount,CloseDate"/>
<apex:remoteObjectModel jsShortHand="con" name="Contact" fields="Id,AccountId,FirstName,LastName,Phone,Email"/>
</apex:remoteObjects>
<script>
var $j = jQuery.noConflict();
$j(document).ready(function() {
$j("#records").jtable({
title: "Accounts",
jqueryuiTheme: true,
saveUserPreferences: false,
paging: true,
pageSize: 10,
pageSizes: [10, 25, 50, 75, 100],
fields: {
Id: {
key: true,
list: false
},
Opportunities: {
title: "",
width: "1%",
sorting: false,
openChildAsAccordion: true,
create: false,
edit: false,
display: function(account) {
return setupChildren(account, opportunityConfig);
}
},
Contacts: {
title: "",
width: "1%",
sorting: false,
openChildAsAccordion: true,
create: false,
edit: false,
display: function(account) {
return setupChildren(account, contactConfig);
}
},
Name: { title: "Name" },
Phone: { title: "Phone" },
Fax: { title: "Fax" }
},
actions: {
listAction: function (postData, jtParams) {
return listAccounts(postData, jtParams);
},
createAction: function (postData) {
return upsert(new SObjectModel.acct(getFields(postData)), getAccountObject);
},
updateAction: function(postData) {
return upsert(new SObjectModel.acct(getFields(postData)), getAccountObject);
}
}
});
$j("#records").jtable("load");
function listAccounts(postData, jtParams) {
var limitVal = jtParams.jtPageSize;
var offsetVal = jtParams.jtStartIndex;
var criteria = {
limit: limitVal,
orderby: [ {Name: "ASC NULLS LAST"} ]
};
// offsetVal must be at least 1
if (offsetVal >= 1) {
criteria.offset = offsetVal;
}
return retrieve(new SObjectModel.acct(), getAccountObject, criteria);
}
function getAccountObject(record) {
return {
Id : record.get("Id"),
Name : record.get("Name"),
Phone : record.get("Phone"),
Fax : record.get("Fax")
};
}
function setupChildren(account, configFunc) {
var config = configFunc(account);
var openLink = $j("<img src='" + config.img + "' title='" + config.title + "' alt='" + config.title + "' />");
openLink.click(function(event) {
event.preventDefault();
$j("#records").jtable("openChildTable", openLink.closest("tr"), config, function(data) {
data.childTable.jtable("load");
});
});
return openLink;
}
function opportunityConfig(account) {
var config = {
title: account.record.Name + " - Opportunities",
img: "{!URLFOR($Resource.res, 'opportunities32.png')}",
actions: {
listAction: function(data) {
return listOpportunities(account);
},
updateAction: function(postData) {
return upsert(new SObjectModel.opp(getFields(postData)), getOpportunityObject);
},
createAction: function(postData) {
return upsert(new SObjectModel.opp(getFields(postData)), getOpportunityObject);
}
},
fields: {
AccountId: {
type: "hidden",
defaultValue: account.record.Id
},
Id: {
key: true,
create: false,
edit: false,
list: false
},
Name: {
title: "Name",
width: "30%"
},
Amount: {
title: "Amount",
display: function(data) {
if (data.record.Amount) {
return data.record.Amount.toLocaleString();
}
return "-";
}
},
StageName: {
title: "Stage",
type: "text"
},
Probability: {
title: "Probability",
type: "text",
display: function(data) {
return data.record.Probability + "%"
}
},
CloseDate: {
title: "Close Date",
type: "date",
display: function(data) {
return new Date(data.record.CloseDate).toDateString();
}
}
}
};
function listOpportunities(account) {
return retrieve(new SObjectModel.opp(), getOpportunityObject, {
limit: 100,
where: { AccountId: { eq: account.record.Id } }
});
}
function getOpportunityObject(record) {
return {
Id : record.get("Id"),
Name : record.get("Name"),
AccountId : record.get("AccountId"),
Amount : record.get("Amount"),
StageName : record.get("StageName"),
Probability : record.get("Probability"),
CloseDate : record.get("CloseDate")
};
}
return config;
}
function contactConfig(account) {
var config = {
title: account.record.Name + " - Contacts",
img: "{!URLFOR($Resource.res, 'contacts32.png')}",
actions: {
listAction: function(data) {
return listContacts(account);
},
createAction: function(postData) {
return upsert(new SObjectModel.con(getFields(postData)), getContactObject);
},
updateAction: function(postData) {
return upsert(new SObjectModel.con(getFields(postData)), getContactObject);
}
},
fields: {
AccountId: {
type: "hidden",
defaultValue: account.record.Id
},
Id: {
key: true,
create: false,
edit: false,
list: false
},
FirstName: { title: "First Name" },
LastName: { title: "Last Name" },
Phone: { title: "Phone" },
Email: { title: "Email" }
}
};
function listContacts(account) {
return retrieve(new SObjectModel.con(), getContactObject, {
limit: 20,
where: { AccountId: { eq: account.record.Id } }
});
}
function getContactObject(record) {
return {
Id : record.get("Id"),
FirstName : record.get("FirstName"),
LastName : record.get("LastName"),
Phone: record.get("Phone"),
Email: record.get("Email")
};
}
return config;
}
function retrieve(modelVar, objectConverterFunc, config) {
return $j.Deferred(function (dfd) {
modelVar.retrieve(config,
function(err, records, event) {
if (err) {
handleErr(dfd, err);
} else {
// construct the result in the jTable expected format
var data = {
Result: "OK",
Records: [],
TotalRecordCount: event.result.TotalRecordCount
};
// add the records to the results
records.forEach(function(record) {
data.Records.push(objectConverterFunc(record));
});
dfd.resolve(data);
}
}
);
});
}
function upsert(modelVar, objectConverterFunc) {
return $j.Deferred(function(dfd) {
modelVar.upsert(function(err, result) {
if (err) {
handleErr(dfd, err);
} else {
var rec = objectConverterFunc(modelVar);
rec.Id = result[0];
dfd.resolve({
Result: "OK",
Record: rec
});
}
});
});
}
function handleErr(dfd, err) {
var data = {
Result: "ERROR",
Message: err
};
dfd.resolve(data);
}
function getFields(postData) {
// extract the fields (simple name/values)
// from the postData query string
var rec = {};
var pairs = postData.split("&");
var i, pair;
for (i = 0; i < pairs.length; i++) {
pair = pairs[i].split("=");
rec[pair[0]] = decodeURIComponent( pair[1].replace(/\+/g, ' ') );
}
return rec;
}
});
</script>
<div id="records"></div>
</apex:page>
public with sharing class jTableAccountsController {
@RemoteAction
public static Map<String, Object> retrieveAccts(String type, List<String> fields, Map<String, Object> criteria) {
// Retrieve using the standard retrieve
Map<String, Object> result = RemoteObjectController.retrieve(type, fields, criteria);
// Add in the total record count for the current user. Needed for pagination
Integer numOwnedAccts = [
SELECT Count()
FROM Account
WHERE OwnerId =: UserInfo.getUserId()
];
// Create a new map since the result map is read-only
Map<String, Object> customResult =
new Map<String, Object> {'TotalRecordCount'=> numOwnedAccts};
customResult.putAll(result);
return customResult;
}
}
@peterknolle
Copy link
Author

This is code from my article Visualforce Remote Objects with jTable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment