Персонализираните потребителски интерфейси могат да бъдат обезсърчително нещо за въвеждане в Salesforce организацията на клиента, ако екипът няма налични ресурси за разработка, за да направи промени в бъдеще. Това може да бъде смекчено предварително чрез изграждане на конфигурируеми потребителски интерфейси, които позволяват на администратора да актуализира слоя на изгледа и неговите компоненти чрез щраквания, а не код. В този пример ще проверим страница на Visualforce, която обслужва приложение на React, и как това приложение на React уважава конфигурируемите метаданни в рамките на организацията.
Ето кратко демонстрационно видео, което показва това от гледна точка на администратора:
Нашето приложение използва стандартните опции за набор полета и персонализиран тип метаданни в менюто за настройка на Salesforce и ги комбинира с Реактор за набор полета repo за описание на метаданните в контекста на текущия потребител. Нека да се потопим и да видим как тези три компонента работят заедно с нашето клиентско приложение React, за да създадем потребителски интерфейс, който може да се конфигурира от администратора.
Персонализирани типове метаданни: алтернатива на персонализираните настройки
Персонализираните типове метаданни бяха пуснати през лятото на 2015 г. като алтернатива на персонализираните настройки. С тях разработчиците и администраторите могат да разгръщат данните във всеки персонализиран тип метаданни заедно с набори от промени, като по този начин отделят потенциала за несъответствия в данните между среди като част от версиите и обновяванията на пясъчника.
В рамките на приложението използваме персонализирани типове метаданни, за да дефинираме секции от потребителския интерфейс, как си взаимодействат тези секции и обектите/полетата, които съставят тази секция. Име на програмист на всеки запис ни позволява да препращаме към този раздел в кода на нашето приложение React. Останалите полета позволяват на администраторите да контролират аспектите на потребителския интерфейс:
- Квадратчето за отметка Active__c позволява контрол дали да се показва този раздел
- Section_Order__c определя как секциите се показват една спрямо друга
- Object_Name__c указва обекта, към който принадлежи наборът полета
- Field_Set_Name__c свързва набор от полета към този конкретен раздел
Полеви набори: изпробвани и вярни
Наборите полета съществуват от известно време и са доста лесни за внедряване в рамките на страница на Visualforce, като се използват стандартни компоненти като <apex:repeat>
. Друга употреба за набори от полета е в Apex за контрол на полета, използвани в заявка или операция за клониране. В нашето приложение наборите от полета позволяват на администратора да дефинира набора от полета, които трябва да се показват в даден раздел на потребителския интерфейс, и гарантира, че контролерът Apex включва тези полета, когато обслужва данни към потребителския интерфейс.
Нашата употреба на набори от полета е да позволи на администратора да контролира кои полета трябва да се показват на базата на обект и за разработчика да ги използва за описание на атрибутите на полето и достъпността за текущия
потребител.
Field Set Reactor: Помощна програма в помощ на разработчиците на SPA
След като вземем персонализираните типове метаданни за текущата страница заедно с наборите от полета, трябва да опишем полетата в контекста на достъпа на текущия потребител, за да гарантираме, че нашият потребителски интерфейс е гъвкав и съответства на текущата конфигурация. Field Set Reactor има метод, който връща колекция от вътрешния клас FieldDetails, който прави всичко - от предоставяне на API име и тип данни, до достъп за четене/редактиране на потребителя за полето и етикета потребителят вижда в стандартните страници.
За всеки набор от полета, който се появява в персонализираните типове метаданни за нашата страница, ние получаваме колекция от FieldDetails и поставяме това в карта с ключ като DeveloperName на персонализирания тип метаданни .
@RemoteAction public static Map<String, List<FieldSetReactor.FieldDetails>> getFieldDetails(List<Dynamic_Page_Mapping__mdt> pageMapping) { Map<String, List<FieldSetReactor.FieldDetails>> sectionFieldDetails = new Map<String, List<FieldSetReactor.FieldDetails>>(); for(Dynamic_Page_Mapping__mdt pageMap : pageMapping) { List<FieldSetReactor.FieldDetails> fieldDetails = FieldSetReactor.getFieldDetails(pageMap.Field_Set_Name__c, pageMap.Object_Name__c); sectionFieldDetails.put(pageMap.Field_Set_Name__c, fieldDetails); } return sectionFieldDetails; }
Обединяване заедно в един пакет
Цялата тази логика се връща на страницата на Visualforce като пакет, наречен AccountManagementState, дефиниран в рамките на AccountManagementController. Този пакет представлява не само секциите, които съставляват страницата на Visualforce, но и данните, които ще предадем на всяка от секциите като props
. Когато страницата се зареди, JavaScript отдалеченото извиква метода getInitialState в AccountManagementController и след това обратното извикване анализира отговора в React state
.
Ето какво всеки компонент на върнатата стойност от getInitialState:
- sectionMap колекция от нашия персонализиран тип метаданни
- fieldMap карта, където всеки ключ е персонализираните записи на типа метаданни DeveloperName, а стойността е колекция от FieldDetails (от предишния раздел)
- account записът на акаунта с неговите полета
- контакти колекция от контакти, свързани с акаунта
- opps колекция от възможности, свързани с акаунта
От предния край: Интегриране с React
Нашите помощни модули и React компоненти съществуват в dev/js, а най-горният компонент е App.js. По време на метода на жизнения цикъл componentWillMount
ние грабваме ID на записа от URL адреса, извикваме setState
, за да уловим ID на записа и използваме обратното извикване, за да предадем this
към getInitialState.
getInitialState се импортира от DataHandler.js, който е модул, който съдържа взаимодействията между клиента и Apex контролера; имайте предвид, че едно и също име за функциите от страната на клиента и от страна на сървъра е удобно, но не е задължително.
componentWillMount() { const recordId = getUrlParameters()[“id”]; this.setState({ RecordId: recordId }, () => {getInitialState(this)}); }
Нашият метод getInitialState в DataHandler.js използва отдалечено управление на JavaScript, за да извика метода getInitialStateна AccountManagementController и предава RecordIdот state
. Използваме функция със стрелка като обратно извикване и разделяме единичния пакет на различни части на нашия React state
и предаваме съответните структури на всеки от нашите React компоненти в App.js.
<div className=”app-container”> <AccountHeader Fields={this.state.Fields} Section={this.state.Sections.get(‘Account_Header’)} Account={this.state.Account} /> <ContactTable Fields={this.state.Fields} Section={this.state.Sections.get(‘Contact_Table’)} Contacts={this.state.Contacts} /> <OppTable Fields={this.state.Fields} Section={this.state.Sections.get(‘Opp_Table’)} Opps={this.state.Opps} /> </div>
Фокусирайки се конкретно върху компонента AccountHeader.js, ние обикаляме масива, върнат от this.props.Fields.get('Account_Header')
, за да създаваме итеративно компоненти AccountHeaderField.
<ul className=”slds-grid slds-page-header__detail-row”> { this.props.Fields.get(‘Account_Header’).map(item => <AccountHeaderField key={item.name} Field={item} Account={this.props.Account} />) } </ul>
Динамично подреждане на секции
Бяхме обещали доставка на динамично подредени секции и това изобщо не изисква JS. Използвайки изключително flexbox, можем да зададем свойството order на всяко div от най-високо ниво, изобразено от нашия AccountHeader, ContactTable и компоненти OppTable.
Нека да разгледаме този пример в метода за изобразяване на AccountHeader:
if(this.props.Fields.get(‘Account_Header’) != null) { let flexOrder = {order: this.props.Section.Section_Order__c}; return( <div style={flexOrder} className=”slds-page-header”>
Преди да върнем нашия JSX, ние създаваме обект, който съдържа стилове, който включва нашето свойство order. Предаваме това като вграден стил във връщането и по този начин той взаимодейства с другите секции въз основа на подреждането на flexbox.
Нашите стилове в dev/css/App.css са супер кратки; искаме да използваме flexbox, като основната ос е вертикална. Вградените стилове във всеки компонент обработват подреждането и сме готови.
div.app-container { display: flex; flex-direction: column; }
Идеи за реализация
Въпреки че това е тривиален пример, има място за разширяване на тази рамка. Ето няколко идеи за това как можете да приложите това във вашите проекти за разработка и да помогнете на администраторите да конфигурират своите страхотни потребителски интерфейси:
- Свържете потребителски типове метаданни към конкретни типове записи за обект
- Дефинирайте страници, които трябва да се появят в многоетапен съветник
- Задълбочете се в персонализирането на потребителския интерфейс с Ръчното оразмеряване на SLDS Grid, което позволява на администраторите да контролират как да се показват във всеки раздел
Тестово шофиране на приложението
Преминете към GitHub repo и следвайте стъпките по-долу, за да изпробвате това във вашата организация:
- Разклонете хранилището и клонирайте към вашата локална машина
cd
в папката на вашия проект и стартирайтеnpm install
- След като зависимостите се заредят,
webpack --watch
за възстановяване на вашия файл resource-bundles/AccountManagement.resource/js/app.js, когато компонентите в dev/* се променят - Използвайте функцията Convert to MavensMate Project, за да внедрите това във вашата организация с помощта на MavensMate с Sublime Text / Atom / VS Code
- Разположете своя пакет AccountManagement.resource на сървъра и обновете страницата си AccountManagement
Ако сте правили нещо подобно или искате да споделите мислите си, не се колебайте да оставите коментар по-долу, проблем или PR в repo или чрез Twitter @RogerMitchell.