User mode database operations.
In the '24 Winter update, we can choose how code runs—either with system-level permissions or in a more secure user mode.
// Using user mode in a SOQL query
List<Account> acc = [SELECT Id FROM Account WITH USER_MODE];
// Inserting a new account in user mode
Account newAcc = new Account(Name='test');
insert as user newAcc;
Custom error messages in record-triggered flows.
The error messages display in a window on the overall record page or as an inline error on a specific field. The associated record change is rolled back. Error messages can be created for before-save and after-save flows.
When a user performs an action like deleting a record that triggers a flow, sometimes the flow runs into an error. Before, when the flow failed, it wasn’t possible to display a specific error message to the user.
Add a Custom Error Message element (1)
Choose where to display the error message (2)
Enter the error message text (3).
Improved conditional directives in Lightning web components.
Instead of using the legacy if:true and if:else directives, we can now use lwc:if, lwc:elseif, and lwc:else conditional directives. This change is applied to LWC OSS as well.
<!-- example.html -->
<template>
<template lwc:if={expression1}>
Statement 1
</template>
<template lwc:elseif={expression2}>
Statement 2
</template>
<template lwc:else>
Statement 3
</template>
</template>
Both lwc:elseif and lwc:else must be started by either lwc:if or lwc:elseif.
Conditional directives are used on nested <template>, or <div> tags or other HTML elements, on the custom components like <c-custom-cmp>
Complex expressions are not supported. To achieve that, we have to use a getters in our JS class.
For Loops with Iterable.
We can iterate through lists or sets using an Iterable variable in a for loop.
Iterable<String> stringIterator = new List<String>{'Hello', 'World!'};
for (String str : stringIterator) {
System.debug(str);
}
/* This example implements an Iterable interface and
then iterates through the strings in the returned set of strings. */
public class MyIterable implements Iterable<String> {
public Iterator<String> iterator() {
return new Set<String>{'Hello', 'World!'}.iterator();
}
}
for (String str : new MyIterable()) {
System.debug(str);
}
Comparator interface and Collator class for sorting.
The List class now supports the new Comparator interface, we can implement different sort orders in our code by using List.sort(
) with .Comparator
parameter.
Implement the compare()
method of the System.Comparator
interface, and specify the Comparator as a parameter to List.sort()
. Your implementation must explicitly handle null inputs in the compare()
method to avoid a null pointer exception. This example implements two different ways of sorting employees.
public class Employee {
private Long id;
private String name;
private Integer yearJoined;
// Constructor
public Employee(Long i, String n, Integer y) {
id = i;
name = n;
yearJoined = y;
}
public String getName() { return name; }
public Integer getYear() { return yearJoined; }
}
// Class to compare Employees by name
public class NameCompare implements Comparator<Employee> {
public Integer compare(Employee e1, Employee e2) {
if(e1?.getName() == null && e2?.getName() == null) {
return 0;
} else if(e1?.getName() == null) {
return -1;
} else if(e2?.getName() == null) {
return 1;
}
return e1.getName().compareTo(e2.getName());
}
}
// Class to compare Employees by year joined
public class YearCompare implements Comparator<Employee> {
public Integer compare(Employee e1, Employee e2) {
// Guard against null operands for ‘<’ or ‘>’ operators because
// they will always return false and produce inconsistent sorting
Integer result;
if(e1?.getYear() == null && e2?.getYear() == null) {
result = 0;
} else if(e1?.getYear() == null) {
result = -1;
} else if(e2?.getYear() == null) {
result = 1;
} else if (e1.getYear() < e2.getYear()) {
result = -1;
} else if (e1.getYear() > e2.getYear()) {
result = 1;
} else {
result = 0;
}
return result;
}
}
@isTest
private class EmployeeSortingTest {
@isTest
static void sortWithComparators() {
List<Employee> empList = new List<Employee>();
empList.add(new Employee(101,'Joe Smith', 2020));
empList.add(new Employee(102,'J. Smith', 2020));
empList.add(new Employee(25,'Caragh Smith', 2021));
empList.add(new Employee(105,'Mario Ruiz', 2019));
// Sort by name
NameCompare nameCompare = new NameCompare();
empList.sort(nameCompare);
// Expected order: Caragh Smith, J. Smith, Joe Smith, Mario Ruiz
Assert.areEqual('Caragh Smith', empList.get(0).getName());
// Sort by year joined
YearCompare yearCompare = new YearCompare();
empList.sort(yearCompare);
// Expected order: Mario Ruiz, J. Smith, Joe Smith, Caragh Smith
Assert.areEqual('Mario Ruiz', empList.get(0).getName());
}
}
Source: Trailhead