Flutter Channel Integration
Workbooks communicate with Flutter through the FlutterChannel JavaScript bridge. All messages are JSON-encoded strings.
Required JavaScript Callbacks
Every workbook must implement these two global functions:
handleFlutterMessage
Receives responses from Flutter after save/load/check operations:
window.handleFlutterMessage = function(message) {
const data = JSON.parse(message);
switch(data.type) {
case 'saveResult': handleSaveResult(data.data); break;
case 'loadResult': handleLoadResult(data.data); break;
case 'responseExistsResult': handleResponseExists(data.data); break;
}
};
onFlutterChannelReady
Called when the Flutter WebView channel is initialized:
window.onFlutterChannelReady = function() {
checkForExistingResponses();
};
Message Formats (JS to Flutter)
Save Workbook Response
window.FlutterChannel.postMessage(JSON.stringify({
action: 'saveWorkbookResponse',
responseData: workbookData,
fileName: FILE_NAME // e.g. "C14ENB1_response.json"
}));
Load Workbook Response
window.FlutterChannel.postMessage(JSON.stringify({
action: 'loadWorkbookResponse',
fileName: FILE_NAME
}));
Check Response Exists
window.FlutterChannel.postMessage(JSON.stringify({
action: 'checkResponseExists',
fileName: FILE_NAME
}));
Response Handler Functions
handleSaveResult
function handleSaveResult(data) {
saveInProgress = false;
if (data.success) {
showStatus('saved');
setTimeout(() => showStatus('idle'), 2000);
} else {
showStatus('error');
setTimeout(() => showStatus('idle'), 3000);
}
}
handleLoadResult
function handleLoadResult(data) {
if (data.success && data.data) {
savedData = data.data.data; // Note: nested data.data.data
populateFormWithSavedData(savedData);
showStatus('idle');
} else {
showStatus('idle');
}
}
Important: When loading data, access nested fields with data.data.data — the response wraps the actual workbook data inside a data property.
handleResponseExists
function handleResponseExists(data) {
if (data.exists) {
loadExistingResponses();
} else {
showStatus('idle');
}
}
Event Listener Setup
Every workbook must attach auto-save to all interactive elements:
function setupEventListeners() {
// Standard form elements
document.querySelectorAll('input, textarea, select').forEach(el => {
el.addEventListener('input', triggerAutoSave);
el.addEventListener('change', triggerAutoSave);
});
// Radio buttons and checkboxes
document.querySelectorAll('input[type="radio"], input[type="checkbox"]').forEach(el => {
el.addEventListener('change', triggerAutoSave);
});
// Content editable elements
document.querySelectorAll('[contenteditable="true"]').forEach(el => {
el.addEventListener('input', triggerAutoSave);
});
// Custom interactive elements (calendars, sliders, etc.)
document.querySelectorAll('.interactive-element').forEach(el => {
el.addEventListener('click', () => triggerAutoSave());
});
}