# Formevents

Custom code, attatched to an entity, getting called at different times

# Understanding formevents

## Execution order

<div drawio-diagram="304"><img src="https://docs.tsnocode.com/uploads/images/drawio/2025-08/ERW1jo26XHWilw0E-drawing-3-1755000921.png" alt=""/></div>

# Creating the codeunit

1. Make sure that **p2eShared.jar** is included in the project
2. Create a new class that extends

```
   com.tsnocode.codeunit.CodeunitFormevents
```

# LIST level event hooks

```java
public String appendListPageHead() { return ""; }
public String appendListPageFoot() { return ""; }
```

```java
public void beforeSelectList() throws Exception {}
public void beforeRenderList() throws Exception {}
```

#### <span class="mw-headline" id="bkmrk-list-execution-order-1">LIST execution order</span>

1. **beforeSelectList**
2. Gather form data from database 
    1. dataFilterActive &gt; dataFilterHandler
    2. listFilterActive &gt; listFilterHandler
3. **beforeRenderList**
4. Return list to user

# ITEM level event hooks

```java
public String appendItemPageHead() { return ""; }
public String appendItemPageFoot() { return ""; }
```

```java
public void beforeSelectItem() throws Exception {}
public void beforeChangeItem() throws Exception {}
public void beforeUpdateItem() throws Exception {}
public void beforeRenderItem() throws Exception {}
public void afterUpdateItem() throws Exception {}

public boolean afterUpdateRedirectActive() { return false; }
public String afterUpdateRedirectContent()   { return null; }
```

#### <span class="mw-headline" id="bkmrk-item-execution-order-1">ITEM execution order: viewing data</span>

1. **beforeSelectItem**
2. Gather form data from database 
    - dataFilterActive &gt; dataFilterHandler
    - itemFilterActive &gt; itemFilterHandler
3. **beforeRenderItem**
4. Return form to user

#### <span class="mw-headline" id="bkmrk-item-execution-order-3">ITEM execution order: posting data</span>

1. **beforeSelectItem**
2. Gather form data from database
3. **beforeChangeItem**
4. Update field values
5. **beforeUpdateItem**
6. Write changes to database
7. **afterUpdateItem**
8. if NO OTHER ACTION: 
    - **afterUpdateRedirectActive**
    - if TRUE 
        - **afterUpdateRedirectContent**
9. Return content to user

# FILTER event hooks

Filters will help you build customized permission schemes. They are called for **both** LIST and ITEM commands.

```java
@Override
protected boolean dataFilterActive() {
    return true;
}
@Override
protected void dataFilterHandler(StringBuilder sql) {
    sql.append(" AND something");
}
```

In some cases you only want the filter to trigger for **either** LIST or ITEM commands

```java
itemFilterActive() {}
itemFilterHandler(StringBuilder sql) { return sql; }
listFilterActive() {}
listFilterHandler(StringBuilder sql) { return sql; }
```

### <span class="mw-headline" id="bkmrk-examples-1">Examples</span>

The xxxFilterActive tells if the filter is active

```java
boolean dataFilterActive() { return !s.isAdministor(); }
```

The xxxFilterHandler modifies the SQL used to fetch data

```java
void dataFilterHandler(StringBuilder sql) { sql.append(" AND CATEGORY NOT IN (123,456,789)"); }
```

# Event firing details

#### <span class="mw-headline" id="bkmrk-event-firing-global-1">Event firing global</span>

The following events are ALLWAYS fired

- beforeSelectList
- beforeSelectItem
- beforeChangeItem
- beforeUpdateItem
- afterUpdateItem

#### <span id="bkmrk-"></span><span class="mw-headline" id="bkmrk-event-firing-in-ui-%28-1">Event firing in UI (reserved for normal users)</span>

The following events will NOT be fired during imports etc.

- appendListPageHead
- appendListPageFoot
- beforeRenderList
- appendItemPageHead
- appendItemPageFoot
- beforeRenderItem

#### <span class="mw-headline" id="bkmrk-event-firing-in-ui-d-1">Event firing in UI depending on user actions</span>

The following events are SOMETIMES be fired for normal users depending on navigation

- afterUpdateRedirectActive 
    - Not executed in SUBFORM mode
    - Not executed in during imports etc.
- afterUpdateRedirectContent 
    - Depends on a TRUE result from afterUpdateRedirectActive()