Skip to content

Instantly share code, notes, and snippets.

@kerbymart
Created January 30, 2026 06:08
Show Gist options
  • Select an option

  • Save kerbymart/e83dae6dc38c61bc996956ad03110496 to your computer and use it in GitHub Desktop.

Select an option

Save kerbymart/e83dae6dc38c61bc996956ad03110496 to your computer and use it in GitHub Desktop.
# Advanced TeaVM Flavour Implementation Patterns and Techniques
## Table of Contents
* [1\. Introduction](#org1)
* [2\. Advanced Component Patterns](#org2)
* [2.1. Dynamic Component Composition](#org2.1)
* [2.2. Type-Specific Component Rendering](#org2.2)
* [2.3. Conditional Component Selection](#org2.3)
* [2.4. Dynamic Component Creation with Fragments](#org2.4)
* [2.5. Popup/Modal Component Pattern](#org2.5)
* [2.6. Delegate Pattern for Component Communication](#org2.6)
* [2.7. Component Destruction and Resource Management](#org2.7)
* [3\. Entity Data Model Architecture](#org3)
* [3.1. Typed Property System](#org3.1)
* [3.2. JSON Persistence with @JsonPersistable](#org3.2)
* [3.3. Property Hierarchy and Type Management](#org3.3)
* [3.4. Dynamic Schema Management](#org3.4)
* [3.5. Entity Relationship Patterns](#org3.5)
* [3.6. Dynamic Property Addition to Entities](#org3.6)
* [4\. Advanced UI Patterns](#org4)
* [4.1. Interactive Table Components](#org4.1)
* [4.2. Dynamic Property Management](#org4.2)
* [4.3. Complex Form Handling](#org4.3)
* [4.4. Custom JavaScript Integration](#org4.4)
* [4.5. Asynchronous vs Synchronous Event Handling](#org4.5)
* [4.6. Dynamic Content Injection](#org4.6)
* [5\. Template and Component Architecture](#org5)
* [5.1. Slot-Based Component Architecture](#org5.1)
* [5.2. Supplier Pattern for Dynamic Values](#org5.2)
* [5.3. Template Composition with <?use ?> Directive](#org5.3)
* [6\. Component Communication Patterns](#org6)
* [6.1. Mouse Event Handling Techniques](#org6.1)
* [6.2. Dynamic Component Instantiation](#org6.2)
* [6.3. State Management Strategies](#org6.3)
* [7\. Performance Optimization Techniques](#org7)
* [7.1. Lazy Initialization Patterns](#org7.1)
* [7.2. Efficient Data Binding](#org7.2)
* [7.3. Memory Management](#org7.3)
* [7.4. Component Lifecycle Management](#org7.4)
* [7.5. Proper Cleanup with destroy() Method](#org7.5)
## 1. Introduction
This documentation provides comprehensive insights into advanced TeaVM Flavour implementation patterns and techniques, combining both universal best practices and specific implementation strategies. Unlike the general Flavour documentation, this guide explores real-world patterns that extend beyond basic usage, focusing on sophisticated approaches used in complex applications.
The guide covers advanced component patterns, sophisticated data modeling techniques, UI interaction patterns, and performance optimization strategies that complement the standard Flavour documentation. These insights provide deeper understanding of how Flavour concepts can be implemented in sophisticated applications while maintaining best practices for maintainability and performance.
## 2. Advanced Component Patterns
This section covers advanced component patterns that extend beyond the standard Flavour component usage, providing more sophisticated ways to compose and manage UI components.
### 2.1 Dynamic Component Composition
Flavour applications often require sophisticated dynamic component composition patterns, particularly in data-driven interfaces like tables or grids.
**Key Pattern**: Type-based component selection
Applications can dynamically select different cell components based on data types:
```html
<std:foreach var="property" in="entity.properties">
<std:if condition="property.type.equals('String')">
<custom:text-cell value="property"/>
</std:if>
<std:if condition="property.type.equals('List')">
<custom:list-cell value="property"/>
</std:if>
<std:if condition="property.type.equals('Boolean')">
<custom:boolean-cell value="property"/>
</std:if>
</std:foreach>
```
This pattern allows the same container structure to handle different data types with appropriate UI controls, providing flexibility while maintaining consistency.
### 2.2 Type-Specific Component Rendering
Applications can implement a strategy pattern for rendering different property types:
**String Properties**: Use text input components
**Boolean Properties**: Use checkbox components
**List Properties**: Use dropdown or list selection components
**Other Types**: Can be extended with additional conditional blocks
This approach provides:
- **Consistent UI**: All properties follow the same rendering pattern
- **Extensibility**: New property types can be added without breaking existing code
- **Type Safety**: Each property type gets appropriate UI controls
### 2.3 Conditional Component Selection
A powerful pattern used throughout sophisticated Flavour applications is conditional component selection based on runtime data:
```html
<std:if condition="isSelected(item.id)">
<img src="icons/checked.svg" alt="" event:click="unselect(item.id)">
</std:if>
<std:if condition="not isSelected(item.id)">
<img src="icons/unchecked.svg" alt="" event:click="select(item.id)">
</std:if>
```
This pattern allows for dynamic UI that responds to application state, showing different components based on conditions.
### 2.4 Dynamic Component Creation with Fragments
Flavour allows for dynamic component creation using the Fragment pattern. This technique enables runtime creation of UI components based on data or user interactions.
Example implementation:
```java
public static void show(Content content, HTMLElement wrapper, ValueChangeListener<String> changeListener) {
PopupComponent popup = new PopupComponent(Templates.create(content));
popup.wrapper = wrapper;
popup.component = Templates.bind(popup, popup.wrapper);
// ...
}
```
The `Templates.create()` method creates a fragment from a content object, allowing for dynamic UI generation. This is particularly useful for modal dialogs, popups, and other contextual UI elements that need to be created on demand.
### 2.5 Popup/Modal Component Pattern
Applications implement sophisticated popup systems that demonstrate how to handle complex UI interactions:
```java
public class PopupComponent {
private Fragment content;
private Component component;
private HTMLElement wrapper;
private ValueChangeListener<String> changeListener;
public static void show(Content content, HTMLElement wrapper, ValueChangeListener<String> changeListener) {
PopupComponent popup = new PopupComponent(Templates.create(content));
popup.wrapper = wrapper;
popup.component = Templates.bind(popup, popup.wrapper);
content.setDelegate(new PopupDelegate() {
@Override public void setValue(String value) {
changeListener.changed(value);
popup.close(); // Proper cleanup
}
@Override public void close() {
popup.close();
}
});
}
public void close() {
component.destroy(); // Ensures proper resource cleanup
}
}
```
This pattern combines fragments, delegates, and proper resource management to create reusable popup components.
### 2.6 Delegate Pattern for Component Communication
Applications use a delegate pattern to enable communication between components without tight coupling:
```java
public interface PopupDelegate {
void setValue(String value);
void close();
}
public interface SelectionDelegate {
void selectedValue(String value);
void close();
}
```
Delegates allow child components to communicate with their parents or containing components without knowing the specific implementation details of the parent. This creates a clean separation of concerns and promotes reusability.
### 2.7 Component Destruction and Resource Management
Proper resource management is crucial in single-page applications to prevent memory leaks:
```java
public void close() {
component.destroy(); // Critical for preventing memory leaks
}
```
Always call `component.destroy()` when a component is no longer needed to ensure proper cleanup of event listeners and other resources.
## 3. Entity Data Model Architecture
Advanced Flavour applications implement sophisticated entity data model systems that go beyond basic patterns.
### 3.1 Typed Property System
**Core Architecture**:
```java
@JsonPersistable
public class Entity {
private String entityType;
private String entityId;
private List<String> blobReferences;
private List<String> linkReferences;
private List<Property> properties;
}
public class Property {
private String type; // "String", "Boolean", "Integer", etc.
private String value;
}
```
**Key Features**:
- **Dynamic Typing**: Properties can have different types at runtime
- **Schema Flexibility**: Entities can have different properties without schema changes
- **Extensibility**: New property types can be added without breaking existing code
### 3.2 JSON Persistence with @JsonPersistable
Applications use the `@JsonPersistable` annotation to enable automatic JSON serialization:
```java
@JsonPersistable
public class Entity {
// Properties automatically serialized
}
```
This annotation tells Flavour to generate the necessary code for JSON serialization/deserialization, making it easy to persist data to storage or transmit over networks.
Serialization example:
```java
public void save() {
entities.forEach(entity -> {
String serialized = JSON.serialize(entity).stringify();
// Handle serialized data
});
}
```
### 3.3 Property Hierarchy and Type Management
Applications implement sophisticated property hierarchies:
```
Property (base class)
├── PrimitiveProperty (base class)
│ ├── StringProperty
│ ├── IntegerProperty
│ ├── LongProperty
│ ├── DoubleProperty
│ └── BooleanProperty
├── ListProperty
├── EntityProperty
└── IsProperty (interface)
```
This hierarchy allows for type-safe handling of different property types while maintaining a consistent interface:
```java
public class Property {
private String type; // Tracks the Java type
private String value;
// ...
}
```
The `type` field preserves type information for proper deserialization and validation.
### 3.4 Dynamic Schema Management
Components implement dynamic schema management:
```java
public void addProperty(String propertyName, String propertyType) {
Property newProperty = new Property(propertyType, propertyName);
getProperties().add(newProperty);
// Add property to all existing entities
getEntities().forEach(entity -> {
Property entityProperty = new Property(propertyType, propertyName);
if(!entity.getProperties().contains(entityProperty)) {
entity.getProperties().add(entityProperty);
}
});
}
```
This allows:
- **Runtime Schema Evolution**: Add new properties to existing entities
- **Backward Compatibility**: Existing entities automatically get new properties
- **Consistent Data Structure**: All entities maintain the same property structure
### 3.5 Entity Relationship Patterns
The entity model supports complex relationships:
**Blob References**: `List<String> blobReferences` - References to binary data
**Link References**: `List<String> linkReferences` - References to related entities
**Property Collections**: `List<Property> properties` - Dynamic attributes
### 3.6 Dynamic Property Addition to Entities
Applications demonstrate how to dynamically add properties to entities and ensure they're propagated to all existing entities:
```java
public void addProperty() {
getProperties().add(new Property(propertyType, propertyName));
getEntities().forEach(entity -> {
Property entityProperty = new Property(propertyType, propertyName);
if(!entity.getProperties().contains(entityProperty)) {
entity.getProperties().add(entityProperty); // Add to existing entities
}
});
}
```
This pattern ensures data consistency when schema changes occur dynamically.
## 4. Advanced UI Patterns
### 4.1 Interactive Table Components
Advanced table components implement several sophisticated UI patterns:
**Dynamic Row Addition**:
```java
public void addRow() {
getEntities().add(new Entity(generateId(), "default", new ArrayList<>(properties)));
}
```
**Property Management**:
```java
public void addProperty() {
// Adds property to schema and all existing entities
}
```
**Data Serialization**:
```java
public void save() {
entities.forEach(entity -> {
String serialized = JSON.serialize(entity).stringify();
// Handle serialized data
});
}
```
### 4.2 Dynamic Property Management
Components show advanced form handling:
```java
public void createNewItem() {
// Process form input and add to collection
items.add(new Item(inputValue));
}
```
**Key Features**:
- **Form Validation**: Input handling with proper validation
- **State Management**: Maintaining item lists
- **User Feedback**: Appropriate response mechanisms
### 4.3 Complex Form Handling
Templates show sophisticated form patterns:
```html
<input type="text" html:value="inputValue" html:change="inputValue">
<button event:async-click="createNewItem()">
Save
</button>
```
### 4.4 Custom JavaScript Integration
While Flavour provides powerful templating capabilities, sometimes custom JavaScript is needed for complex DOM manipulations:
```html
<script>
function toggleVisibility(elementId) {
document.getElementById(elementId).classList.toggle("hidden");
document.getElementById(elementId).classList.toggle("visible");
}
</script>
```
Then used in templates:
```html
<div class="..." onclick="toggleVisibility('dropdown-menu')">
```
This hybrid approach allows leveraging both Flavour's reactive capabilities and direct DOM manipulation when needed.
### 4.5 Asynchronous vs Synchronous Event Handling
Applications distinguish between synchronous and asynchronous operations:
```html
<!-- Synchronous event - immediate UI response -->
<button event:click="save()">Save</button>
<!-- Asynchronous event - for operations that may take time -->
<a event:async-click="loadData()">Load Data</a>
```
Use `event:async-click` for operations that might involve network calls or heavy computation to prevent blocking the UI thread.
### 4.6 Dynamic Content Injection
The popup system demonstrates how to inject dynamic content into the DOM:
```java
Content content = new DynamicContent(data);
Popup.show(content, wrapper, newValue -> {
// Handle the new value
});
```
This pattern allows for contextual UI that adapts to the current data state.
## 5. Template and Component Architecture
### 5.1 Slot-Based Component Architecture
Components extend `AbstractWidget` and use slots for proper lifecycle management:
```java
public class CustomComponent extends AbstractWidget {
public CustomComponent(Slot slot) {
super(slot); // Proper initialization with slot
}
// ...
}
```
The `Slot` parameter ensures the component is properly integrated into the Flavour rendering system.
### 5.2 Supplier Pattern for Dynamic Values
Applications use suppliers to provide dynamic values to components:
```java
public class CellComponent extends AbstractWidget {
private Supplier<Property> valueSupplier;
@BindAttribute(name = "value")
public void setValueSupplier(Supplier<Property> valueSupplier) {
this.valueSupplier = valueSupplier;
}
public Property getValue() {
return valueSupplier.get(); // Dynamic value retrieval
}
}
```
This pattern allows components to receive values that may change over time or be computed on demand.
### 5.3 Template Composition with <?use ?> Directive
Applications use template composition to create modular UI:
```html
<!-- In main template -->
<?use table:com.example.components?>
<table:entities-table/>
<!-- In table template -->
<std:foreach var="entity" in="entities">
<?use row:com.example.components?>
<row:item value="entity"/>
</std:foreach>
```
This allows for clean separation of concerns and reusable components across the application.
## 6. Component Communication Patterns
### 6.1 Mouse Event Handling Techniques
Applications use advanced mouse event handling:
```java
public void handleSelection(MouseEvent e) {
HTMLElement element = (HTMLElement) e.getTarget();
String innerText = element.getInnerText();
setSelectedValue(innerText);
e.preventDefault();
}
```
**Key Techniques**:
- **Event Target Access**: Getting the clicked element
- **Text Extraction**: Reading inner text from DOM elements
- **Event Prevention**: Using `preventDefault()` to stop propagation
### 6.2 Dynamic Component Instantiation
The popup system shows advanced component instantiation:
```java
public static void show(Content content, HTMLElement wrapper, ValueChangeListener<String> changeListener) {
Component component = new Component(Templates.create(content));
component.wrapper = wrapper;
component.instance = Templates.bind(component, component.wrapper);
content.setDelegate(new ComponentDelegate() {
@Override public void setValue(String value) {
changeListener.changed(value);
component.close();
}
@Override public void close() {
component.close();
}
});
}
```
### 6.3 State Management Strategies
Applications use several state management patterns:
**Lazy Initialization**:
```java
public List<Item> getItems() {
if(items == null) {
items = new ArrayList<>();
}
return items;
}
```
**Null Safety**:
```java
public List<String> getReferences() {
if(references == null) {
references = new ArrayList<>();
}
return references;
}
```
## 7. Performance Optimization Techniques
### 7.1 Lazy Initialization Patterns
Applications extensively use lazy initialization:
```java
public List<Item> getItems() {
if(items == null) {
items = new ArrayList<>();
}
return items;
}
```
**Benefits**:
- **Memory Efficiency**: Only allocate when needed
- **Performance**: Avoid unnecessary object creation
- **Resource Management**: Defer expensive operations
### 7.2 Efficient Data Binding
Applications use efficient data binding patterns:
**Bidirectional Binding**:
```html
<input type="text" html:value="value" html:change="value">
```
**Conditional Rendering**:
```html
<std:if condition="editing">
<!-- Editable content -->
</std:if>
<std:if condition="not editing">
<!-- Display content -->
</std:if>
```
### 7.3 Memory Management
**Null Checks**: Preventing null pointer exceptions
**Collection Safety**: Safe handling of potentially null collections
**Resource Cleanup**: Proper component destruction with `component.destroy()`
### 7.4 Component Lifecycle Management
Components must properly manage their lifecycle to prevent memory leaks:
```java
public class PopupComponent {
private Component component; // Reference to be cleaned up
// Component is created and bound
public static void show(...) {
// ...
popup.component = Templates.bind(popup, popup.wrapper);
}
// Component must be destroyed when no longer needed
public void close() {
component.destroy(); // Critical cleanup step
}
}
```
### 7.5 Proper Cleanup with destroy() Method
Always call `destroy()` on components when they're no longer needed:
```java
public void close() {
component.destroy(); // Releases all resources associated with the component
}
```
Failure to call `destroy()` can result in memory leaks due to retained event listeners and DOM references.
## Conclusion
This documentation provides comprehensive insights into advanced TeaVM Flavour implementation patterns and techniques, combining both universal best practices and specific implementation strategies. The guide covers sophisticated approaches used in complex applications, extending beyond basic Flavour usage.
The key takeaways include:
- Advanced component composition patterns
- Sophisticated entity data modeling
- Dynamic schema management
- Performance optimization techniques
- Component communication patterns
- Memory and resource management strategies
These insights complement the general Flavour documentation by providing deeper understanding of how Flavour concepts can be implemented in sophisticated applications while maintaining best practices for maintainability and performance.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment