Создадим страницу с использованием Visualforce. Которая будет работать с двумя Salesforce объектами «PC Brand» и «Brand Product», связанными между собой Lookup связью.
Страница будет выводить список брендов, при нажатии на имя бренда в этом списке будут все связанные с ним продукты. О связях между объектами в Salesforce можно почитать тут.
Также на странице можно будет создать продукт для любого из брендов.
Разобьем весь процесс на несколько этапов:
1. Создание объектов в Salesforce;
2. Вывод данных на страницу;
3. Создание объекта на странице;
Страница Visualforce:
<apex:page id="PCBrandsList" controller="PCBrandsListController">
<apex:sectionHeader title="PC Brands" subtitle="All brands"/>
<apex:form>
<apex:pageBlock title="List PC Brands">
<apex:pageBlockSection columns="1">
<apex:pageBlockTable value="{!pcBrands}" var="brand">
<apex:column headerValue="Product">
<apex:commandLink action="{!retrieveProducts}" value="{!brand.Name}" reRender="bProdacts">
<apex:param name="bParam" value="{!brand.id}" assignTo="{!brandId}"/>
</apex:commandLink>
</apex:column>
<apex:column headerValue="Description">
<apex:outputText value="{!brand.About_Brand__c}"/>
</apex:column>
</apex:pageBlockTable>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
<apex:pageBlock title="List Brand Products">
<apex:pageBlockSection columns="1">
<apex:pageBlockTable value="{!brandProducts}" var="product" id="bProdacts">
<apex:column headerValue="Product">
<apex:outputText value="{!product.Name}"/>
</apex:column>
<apex:column headerValue="Motherboard">
<apex:outputText value="{!product.Motherboard__c}"/>
</apex:column>
<apex:column headerValue="HDD Size">
<apex:outputText value="{!product.HDD_Size__c}"/>
</apex:column>
<apex:column headerValue="Ram">
<apex:outputText value="{!product.Ram__c}"/>
</apex:column>
<apex:column headerValue="Video Card">
<apex:outputText value="{!product.Video_card__c}"/>
</apex:column>
<apex:column headerValue="Video Card Size">
<apex:outputText value="{!product.Video_card_size__c}"/>
</apex:column>
</apex:pageBlockTable>
</apex:pageBlockSection>
</apex:pageBlock>
<apex:form id="saveBrand">
<apex:pageBlock title="Add Product">
<apex:pageMessages id="showmsg"></apex:pageMessages>
<apex:pageBlockSection columns="1">
<apex:selectList value="{!bProduct.PC_Brand__c}" size="1" multiselect="false">
<apex:selectOptions value="{!selectValues}"/>
</apex:selectList>
<apex:inputText value="{!bProduct.Name}" required="true"/>
<apex:inputText value="{!bProduct.Motherboard__c}" />
<apex:inputText value="{!bProduct.HDD_Size__c}" />
<apex:inputText value="{!bProduct.Ram__c}" />
<apex:inputText value="{!bProduct.Video_card__c}" />
<apex:inputText value="{!bProduct.Video_card_size__c}" />
<apex:commandButton value="Add product" action="{!save}" reRender="saveBrand"/>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>
Дополнительно про Visualforce компоненты и как они работают можно прочитать здесь.
Контроллер на Apex:
public with sharing class PCBrandsListController {
public Brand_Product__c bProduct{get; set;}
public List<PC_Brand__c> pcBrands{get; set;}
public List<Brand_Product__c> brandProducts{get; set;}
public String brandId{get; set;}
public String selectedvalue{get; set;}
public PCBrandsListController(){
bProduct = new Brand_Product__c();
pcBrands = getPCBrangs();
}
private List<PC_Brand__c> getPCBrangs(){
List<PC_Brand__c> listBrands = [SELECT Id, Name, About_Brand__c FROM PC_Brand__c];
return listBrands;
}
public void retrieveProducts(){
brandProducts = [SELECT Id, Name, Motherboard__c, HDD_Size__c, Ram__c, Video_card__c, Video_card_size__c, PC_Brand__c FROM Brand_Product__c WHERE PC_Brand__c = :brandId];
}
public List<SelectOption> getselectValues(){
List<SelectOption> lOptions = new List<SelectOption>();
for (PC_Brand__c brand : pcBrands){
lOptions.add(new SelectOption(brand.Id, brand.Name));
}
return lOptions;
}
public PageReference save(){
PageReference pageRef = Page.PCBrandsList;
pageRef.setRedirect(true);
try {
insert bProduct;
}catch (Exception e){
ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '"Something went wrong !"'));
}
return pageRef;
}
}
Про Apex контроллер можно почитать здесь.
Подробно что как работает опишу ниже.
Создание объектов в Salesforce.
Создадим два объекта «PC Brand» и «Brand Product».
Описание объектов:
PC Brand
Brand Product
На объекте «Brand Product» будет Lookup поле которое будет ссылаться на объект «PC Brand».
Вывод данных на страницу
Чтобы связать Visualforce страницу с Apex контроллером нужно это прописать в теге apex:page
,
где "PCBrandsListController"
- это имя Apex контроллера.
<apex:page id="PCBrandsList" controller="PCBrandsListController">
Теперь мы сможем обращаться к переменным и методам Apex контроллера.
Данные выводятся в виде таблицы. Для этого используется тег apex:pageBlockTable
:
<apex:pageBlockTable value="{!pcBrands}" var="brand">
<apex:column headerValue="Product">
<apex:commandLink action="{!retrieveProducts}"
value="{!brand.Name}"
reRender="bProdacts">
<apex:param name="bParam" value="{!brand.id}" assignTo="{!brandId}"/>
</apex:commandLink>
</apex:column>
<apex:column headerValue="Description">
<apex:outputText value="{!brand.About_Brand__c}"/>
</apex:column>
</apex:pageBlockTable>
В теге apex:pageBlockTable
атрибут value="{!pcBrands}"
ссылается на переменную из Apex контроллера public List<PC_Brand__c> pcBrands{get; set;}
которая инициализируется в конструкторе контроллера.
Для того чтобы сделать имя бренда кликабельным используем тег apex:commandLink
, где в атрибуте action="{!retrieveProducts}"
ссылаемся на функцию контроллера retrieveProducts()
. Которая выполняется по нажатию на имя бренда. Тег apex:commandLink
имеет дочерний тег apex:param
где Id бренда value="{!brand.id}"
передается в переменную контроллера assignTo="{!brandId}"
вот таким образом.
Теперь чтобы после нажатия на имя бренда у нас обновилась таблица с зависимыми продуктами мы используем атрибут reRender="bProdacts"
тега apex:commandLink
где bProdacts
это значение атрибута Id
из тега <apex:pageBlockTable value="{!brandProducts}" var="product" id="bProdacts">
- таблицы, где выводятся продукты выбранного бренда.
И наконец сама таблица продуктов:
<apex:pageBlockTable value="{!brandProducts}" var="product" id="bProdacts">
<apex:column headerValue="Product">
<apex:outputText value="{!product.Name}"/>
</apex:column>
<apex:column headerValue="Motherboard">
<apex:outputText value="{!product.Motherboard__c}"/>
</apex:column>
<apex:column headerValue="HDD Size">
<apex:outputText value="{!product.HDD_Size__c}"/>
</apex:column>
<apex:column headerValue="Ram">
<apex:outputText value="{!product.Ram__c}"/>
</apex:column>
<apex:column headerValue="Video Card">
<apex:outputText value="{!product.Video_card__c}"/>
</apex:column>
<apex:column headerValue="Video Card Size">
<apex:outputText value="{!product.Video_card_size__c}"/>
</apex:column>
</apex:pageBlockTable>
Здесь в теге apex:pageBlockTable
мы обращаемся к переменной контроллера value="{!brandProducts}"
. Которая устанавливается после нажатия на имя бренда в методе
public void retrieveProducts(){
brandProducts = [SELECT Id, Name, Motherboard__c, HDD_Size__c, Ram__c, Video_card__c, Video_card_size__c, PC_Brand__c FROM Brand_Product__c WHERE PC_Brand__c = :brandId];
}
Создание объекта на странице
Для создания объекта создадим еще одну форму на странице Visualforce:
<apex:form id="saveBrand">
<apex:pageBlock title="Add Product">
<apex:pageMessages id="showmsg"></apex:pageMessages>
<apex:pageBlockSection columns="1">
<apex:selectList value="{!bProduct.PC_Brand__c}" size="1" multiselect="false">
<apex:selectOptions value="{!selectValues}"/>
</apex:selectList>
<apex:inputText value="{!bProduct.Name}" required="true"/>
<apex:inputText value="{!bProduct.Motherboard__c}" />
<apex:inputText value="{!bProduct.HDD_Size__c}" />
<apex:inputText value="{!bProduct.Ram__c}" />
<apex:inputText value="{!bProduct.Video_card__c}" />
<apex:inputText value="{!bProduct.Video_card_size__c}" />
<apex:commandButton value="Add product" action="{!save}" reRender="saveBrand"/>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
Здесь в месте, где стоит тег apex:pageMessages
будет выводиться сообщение об ошибке, если не получается сохранить запись в Salesforce. Сообщение об ошибке в контроллере на страницу Visualforce передается вот так: ApexPages.addmessage(new ApexPages.message(ApexPages.severity.ERROR, '"Something went wrong !"'));
Для инициализации выпадающего списка используется конструкция:
<apex:selectList value="{!bProduct.PC_Brand__c}" size="1" multiselect="false">
<apex:selectOptions value="{!selectValues}"/>
</apex:selectList>
Здесь нужно отметить что в теге <apex:selectOptions value="{!selectValues}"/>
мы обращаемся к функции контроллера getselectValues()
указывая ее имя, но без префикса get
вот так: {!selectValues}
.
В теге apex:commandButton
мы обращаемся к методу action="{!save}"
контроллера страницы. Где и происходит сохранение продукта.
Для того чтобы можно было обращаться к переменным контроллера из Visualforce страницы, нужно чтоб переменные имели геттеры и сеттеры или их сокращенная запись как в нашем примере:
public Brand_Product__c bProduct{get; set;}
public List<PC_Brand__c> pcBrands{get; set;}
public List<Brand_Product__c> brandProducts{get; set;}
public String brandId{get; set;}
public String selectedvalue{get; set;}
В итоге у нас получится вот такая форма: