Filter search with apex and visualforce

Иногда случается так что выпадающий список содержит слишком много записей, что сильно затрудняет поиск необходимых. В таком случае на помощь может прийти динамически фильтруемый список, который будет подбирать записи на лету, в соответствии с тем, что вводит пользователь.


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>

Используем немного стилей для большего удобства. :smirk:

Теперь строка поиска, её неотъемлемой частью станет функция написанная на 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;
    }

}

Думаю что найдутся идеи улучшить данный способ поиска и фильтрации, пишите в комментариях :blush:

4 Likes