This article will give you a few useful examples on how you can leverage the custom form logic feature. Other articles on this topic:

Detailed Code Samples

This section contains a few detailed code samples intended as tutorials to give you more guidance:

Quick and Dirty Code Samples

This section contains some quick examples without much explanation, intended to give you some more ideas of what is possible.

This example adds the Account name to each Contact appearing in the Contact lookup and Contact related list.

global class MyFormLogic implements B25.Form.Customizer {
    
    global void customize(B25.Form form) {
        form.getLookup(B25__Reservation__c.B25__Contact__c).onSearch(new ContactSearchHandler());
        form.getRelatedList(B25__ReservationContact__c.SObjectType).onSearch(new ContactSearchHandler());
    }
    
    global class ContactSearchHandler extends B25.SearchHandler {
        global override B25.SearchResultCollection getSearchResults(B25.SearchContext searchContext) {
            searchContext.setMetaTemplate('{0}', new List<String>{'Account.Name'});
            return searchContext.getDefaultResults();
        }
    }
}
global with sharing class MyFormLogic implements B25.Form.Customizer {
    global void customize(B25.Form form) {
        // Trigger MyGroupHandler when the Group field changes
        form.getField(B25__Reservation__c.B25__Group__c).onUpdate(new MyGroupHandler());
    }
    
    global with sharing class MyGroupHandler extends B25.FormEventHandler {
        global override void handleEvent(B25.FormEvent event, B25.Form form) {
            // Get all members that belong to the group
            Id newGroupId = (Id) event.getNewValue();
            List<B25__Group_Membership__c> groupMembers = [SELECT B25__Contact__c FROM B25__Group_Membership__c WHERE B25__Group__c = :newGroupId];

            // Loop through the members and add the contact to the reservation contacts
            for(B25__Group_Membership__c groupMember : groupMembers){
                B25__ReservationContact__c reservationContact = new B25__ReservationContact__c();
                reservationContact.B25__Contact_Lookup__c = groupMember.B25__Contact__c;
                form.getRelatedList(B25__ReservationContact__c.SObjectType).addRecord(reservationContact);
            }
            
            //This updates the quantity of the reservation to the amount of contacts in the group 
            form.getField(B25__Reservation__c.B25__Quantity__c).updateValue(groupMembers.size());
        }
    }
}
global class ReservationContactAddedHandler extends B25.FormEventHandler {
    global override void handleEvent(B25.FormEvent event, B25.Form form) {
        B25__Reservation__c reservation = form.getReservation();
        if (reservation.B25__Account__c == null || event.getNewValue() != 'all-contacts') {
            return;
        }
        for (Contact contact : [SELECT Id FROM Contact WHERE AccountId = :reservation.B25__Account__c]) {
        	form.getRelatedList(B25__ReservationContact__c.SObjectType).addRecord(new B25__ReservationContact__c(
            	B25__Contact_Lookup__c = contact.Id
            ));
        }
    }
}
global class ReservationContactSearchHandler extends B25.SearchHandler {
	global override B25.SearchResultCollection getSearchResults(B25.SearchContext searchContext) {
    	B25.SearchResultCollection searchCollection = searchContext.getDefaultResults();
        B25.SearchResultCollection updatedCollection = new B25.SearchResultCollection();
        if (searchContext.getForm().getReservation().B25__Account__c != null) {
        	updatedCollection.addSearchResult(
                new B25.SearchResult('all-contacts', 'Add all contacts linked to current account')
                	.setPreventDefault(true)
                	.setIcon('standard:contact_list')
            );
        }
        updatedCollection.addSearchResults(searchCollection.getSearchResults());
        return updatedCollection;
    }
}
global class ReservationTitleUpdateHandler extends B25.FormEventHandler {
    global override void handleEvent(B25.FormEvent event, B25.Form form) {
        String newTitleValue = (String) event.getNewValue();
        List<B25__Reservation_Status__c> matchingStatus = [SELECT Id FROM B25__Reservation_Status__c WHERE Name = :newTitleValue];
        if (!matchingStatus.isEmpty()) {
            form.getField(B25__Reservation__c.B25__Status__c).updateValue(matchingStatus[0].Id);
        }
    }
}
global class ReservationAccountChangeHandler extends B25.FormEventHandler {
    global override void handleEvent(B25.FormEvent event, B25.Form form) {
        String newAccountValue = (Id) event.getNewValue();
        if (String.isBlank(newAccountValue)) {
            for(B25.RelatedListItem item : form.getRelatedList(B25__ReservationContact__c.SObjectType).getItems()) {
                item.remove();
            }
        }
    }
}
global class ReservationStatusChangeHandler extends B25.FormEventHandler {
    global override void handleEvent(B25.FormEvent event, B25.Form form) {
        Id newStatus = form.getReservation().B25__Status__c;
        List<B25__Reservation_Status__c> reservationStatus = [SELECT Id, Name FROM B25__Reservation_Status__c WHERE id = :newStatus];
        if (reservationStatus.isEmpty()) {
            return;
        }
        if (reservationStatus[0].Name == 'Completed') {
            for(B25.RelatedListItem item : form.getRelatedList(B25__ReservationContact__c.SObjectType).getItems()) {
                item.getField(B25__ReservationContact__c.B25__CheckedIn__c).updateValue(true);
            }
        } else {
            for(B25.RelatedListItem item : form.getRelatedList(B25__ReservationContact__c.SObjectType).getItems()) {
                item.getField(B25__ReservationContact__c.B25__CheckedIn__c).updateValue(false);
            }
        }
    }
}
global class ReservationContactRemoveHandler extends B25.FormEventHandler {
    global override void handleEvent(B25.FormEvent event, B25.Form form) {
        B25__ReservationContact__c removedReservationContact = (B25__ReservationContact__c) form.getRelatedList(B25__ReservationContact__c.SObjectType).getItemByGuid(event.getGuid()).getRecord();
        if (form.getReservation().B25__Contact__c == removedReservationContact.B25__Contact_Lookup__c) {
            form.getRelatedList(B25__ReservationContact__c.SObjectType).addRecord(removedReservationContact);
        }
    }
}
global class ResourceLookupSearchHandler extends B25.SearchHandler {
    global override B25.SearchResultCollection getSearchResults(B25.SearchContext searchContext) {
        B25.SearchResultCollection searchCollection = searchContext.getDefaultResults();
        for (B25.SearchResult result : searchCollection.getSearchResults()) {
            result.setIcon(this.getRandomIconName());
        }
        return searchCollection;
    }
    
    private String getRandomIconName() {
        return 'custom:custom' + String.valueOf(Math.Round(Math.Random() * (113-1) + 1));
    }
}
global class FormInitHandler extends B25.FormEventHandler {
    global override void handleEvent(B25.FormEvent event, B25.Form form) {
        if (form.getReservation().Id == null) {
        	form.getField(B25__Reservation__c.B25__Title__c).updateValue('New Reservation');   
        }
    }
}
global class ReservationContactNotesChangeHandler extends B25.FormEventHandler {
    global override void handleEvent(B25.FormEvent event, B25.Form form) {
        String newNotesValue = (String) event.getNewValue();
        if (!String.isBlank(newNotesValue)) {
            if (newNotesValue.containsIgnoreCase('Checked In')) {
                form.getRelatedList(B25__ReservationContact__c.SObjectType).getitembyGuid(event.getGuid()).getField(B25__ReservationContact__c.B25__CheckedIn__c).updateValue(true);
            } else if (newNotesValue.containsIgnoreCase('Checked Out')) {
                form.getRelatedList(B25__ReservationContact__c.SObjectType).getitembyGuid(event.getGuid()).getField(B25__ReservationContact__c.B25__CheckedIn__c).updateValue(false);
            }
        }
    }
}
global class AccountLookupSearchHandler extends B25.SearchHandler {
    global override B25.SearchResultCollection getSearchResults(B25.SearchContext searchContext) {
        B25.SearchResultCollection collection = new B25.SearchResultCollection();
        for (Account account : [SELECT Id, Name, (SELECT Name FROM Contacts LIMIT 2) FROM Account LIMIT 20]) {
            List<String> metaTextArray = new List<String>();
            for (Contact contact : account.Contacts) {
                metaTextArray.add(contact.Name);
            }
            collection.addSearchResult(new B25.SearchResult(account.Id, account.Name).setMetaText(String.join(metaTextArray, ', ')));
        }
        return collection;
    }
}
global with sharing class MyFormLogic implements B25.Form.Customizer {
    global void customize(B25.Form form) {
        // This is where we will add our handlers to the form
        form.getField(B25__Reservation__c.B25__Status__c).onUpdate(new MyStatusHandler());
    }

    global with sharing class MyStatusHandler extends B25.FormEventHandler {
        global override void handleEvent(B25.FormEvent event, B25.Form form) {
            Id newStatusId = (Id) event.getNewValue();
            B25__Reservation_Status__c status = [
                SELECT Name
                FROM B25__Reservation_Status__c
                WHERE Id = :newStatusId
            ];

            if (status.Name == 'Completed') {
                form.getField(B25__Reservation__c.B25__Title__c).hide();
            } else {
                form.getField(B25__Reservation__c.B25__Title__c).show();
            }
        }
    }
}