Иногда случается так что выпадающий список содержит слишком много записей, что сильно затрудняет поиск необходимых. В таком случае на помощь может прийти динамически фильтруемый список, который будет подбирать записи на лету, в соответствии с тем, что вводит пользователь.
1. Вступление
2. Controller
3. Visualforce Page
4. Ресурсы
Вступление
Создание динамически фильтруемого списка будет состоять из 2 основных частей. Написание back-end части в виде контроллера и front-end части в виде Visualforce страницы. Так же, для примера я создал объект Person который содержит всего 3 поля:
- First Name - Text type
- Last Name - Text type
- Email - Email type
Controller
После создание Apex класса, необходимо добавить 2 основных поля для работы с записями.
public List<Person__c> persons{get; set;}
public String searchInput{get; set;}
persons - будет хранить весь список записей типа Person которые хранятся на организации.
searchInput - будет хранить текст введённый в строку поиска.
public PersonSearchController() {
this.persons = [SELECT First_Name__c, Last_Name__c, Email__c FROM Person__c];
}
Инициализируем лист persons в конструкторе.
Теперь 1 из основных частей, метод который и будет учавствовать в фильтрации записей.
public PageReference searchPerson(){
String search = '%' + ApexPages.currentPage().getParameters().get('searchInput') + '%';
try {
persons = [
SELECT
First_Name__c,
Last_Name__c,
Email__c
FROM Person__c
WHERE First_Name__c LIKE :search
OR Last_Name__c LIKE :search
OR Email__c LIKE :search
ORDER BY First_Name__c];
} catch (Exception e) {
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Error!'));
}
return null;
}
Этот метод будет вызываться каждый раз, когда пользователь вводит или как либо меняет значения в строке поиска.
String search = '%' + ApexPages.currentPage().getParameters().get('searchInput') + '%';
При каждом вызове метода мы получаем значение из строки поиска и подставляем его в SOQL запрос.
SELECT
First_Name__c,
Last_Name__c,
Email__c
FROM Person__c
WHERE First_Name__c LIKE :search
OR Last_Name__c LIKE :search
OR Email__c LIKE :search
ORDER BY First_Name__c
После чего коллекция persons будет содержать уже совсем другой набор записей.
Visualforce Page
Для более корректного отображения работы создадим список который будет отображать список всех записей хранящихся на организации и строку ввода для фильтрации этих записей.
<div class="slds-dropdown--length-10">
<apex:pageBlockTable id="personTable" value="{!persons}" var="per" styleClass="slds-table slds-table--bordered slds-table--striped" >
<apex:column headerValue="Full name" value="{!per.First_Name__c} {!per.Last_Name__c}"/>
<apex:column headerValue="Email" value="{!per.Email__c}"/>
</apex:pageBlockTable>
</div>
Используем немного стилей для большего удобства.
Теперь строка поиска, её неотъемлемой частью станет функция написанная на javascript
<script type="text/javascript">
function doSearch() {
var input = document.getElementById(
document.querySelector('[id*="searchInput"]').id
).value;
var inputTrimmed = input.trim();
if(input.length === 0 || inputTrimmed.length > 1) {
searchPerson(inputTrimmed);
}
}
</script>
<div >
<apex:actionFunction name="searchPerson" action="{!searchPerson}" reRender="personTable">
<apex:param name="searchInput" value="" />
</apex:actionFunction>
<apex:inputText id="searchInput" label="Search" onKeyUp="doSearch();" styleClass="slds-input width-to-input" value="{!searchInput}"/>
</div>
На каждое нажатие в строке ввода searchInput вызывается javascript метод doSearch(). Тот в свою очередь подхватывает введённые данные, удаляет пробелы и вызывает метод из контроллера searchPerson. Вызов осуществляется с помощью
<apex:actionFunction action="{!searchPerson}" ..... >
Далее как уже было сказано метод в контроллере делает новый запрос и список persons меняет свои значения. После этого обязательно нужно сделать
reRender="personTable"
что позволит данным на странице отобразиться в новом, соответствующем виде.
Ресурсы
Visualforce page
<apex:page id="personPage" controller="PersonSearchController" showHeader="true" sideBar="false" lightningStylesheets="true">
<apex:slds />
<apex:form >
<div style="min-width: 20%;max-width: 20%;margin-right: 5px;">
<apex:pageBlock >
<div class="searchTitle">
<script type="text/javascript">
function doSearch() {
var input = document.getElementById(
document.querySelector('[id*="searchInput"]').id
).value;
var inputTrimmed = input.trim();
if(input.length === 0 || inputTrimmed.length > 1) {
searchPerson(inputTrimmed);
}
}
</script>
<div >
<apex:actionFunction name="searchPerson" action="{!searchPerson}" reRender="personTable">
<apex:param name="searchInput" value="" />
</apex:actionFunction>
<apex:inputText id="searchInput" label="Search" onKeyUp="doSearch();" styleClass="slds-input width-to-input" value="{!searchInput}"/>
</div>
</div>
<div class="slds-dropdown--length-10">
<apex:pageBlockTable id="personTable" value="{!persons}" var="per" styleClass="slds-table slds-table--bordered slds-table--striped" >
<apex:column headerValue="Full name" value="{!per.First_Name__c} {!per.Last_Name__c}"/>
<apex:column headerValue="Email" value="{!per.Email__c}"/>
</apex:pageBlockTable>
</div>
</apex:pageBlock>
</div>
</apex:form>
</apex:page>
Controller
public with sharing class PersonSearchController {
public List<Person__c> persons{get; set;}
public String searchInput{get; set;}
public PersonSearchController() {
this.persons = [SELECT First_Name__c, Last_Name__c, Email__c FROM Person__c];
}
public PageReference searchPerson(){
String search = '%' + ApexPages.currentPage().getParameters().get('searchInput') + '%';
try {
persons = [
SELECT
First_Name__c,
Last_Name__c,
Email__c
FROM Person__c
WHERE First_Name__c LIKE :search
OR Last_Name__c LIKE :search
OR Email__c LIKE :search
ORDER BY First_Name__c];
} catch (Exception e) {
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Error!'));
}
return null;
}
}
Думаю что найдутся идеи улучшить данный способ поиска и фильтрации, пишите в комментариях