Activities can be configured to listen for an external completion event using the window.postMessage() method and code assets. This functionality allows admins to incorporate external resources, such as forms, into native Acadio activities and use them to track completions. For example, you can embed an external form into an Acadio book activity and the activity will not be marked complete until the form is completed and the event is sent back to the LMS. Additionally, data collected from the external resource will be sent back to Acadio.
IMPORTANT: This functionality requires coding knowledge. Improper configuration or errors within the code can result in a broken student experience. External completion events are not available for SCORM, PDF, Link, Quiz, or Exam activities.
Examples
An example of an acknowledgment form script that returns completion data using the window.postMessage() method is below:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Acknowledgment Form</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.form-container {
max-width: 500px;
margin: auto;
border: 1px solid #ccc;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.checkbox-container {
margin: 15px 0;
}
#submitBtn {
background-color: grey;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: not-allowed;
font-size: 16px;
transition: background-color 0.3s ease, cursor 0.3s ease;
}
#submitBtn:enabled {
background-color: black;
cursor: pointer;
}
</style>
</head>
<body>
<div class="form-container">
<p>
By submitting this form, you acknowledge that you have read, understood, and agreed to the terms and conditions outlined.
</p>
<div class="checkbox-container">
<input type="checkbox" id="ackCheckbox" onclick="toggleSubmitButton()">
<label for="ackCheckbox">I acknowledge and agree to the terms and conditions.</label>
</div>
<button id="submitBtn" disabled onclick="submitForm()">Submit</button>
</div>
<script>
// Initialize the acknowledgment form
console.log('Acknowledgment form initialized');
// Listen for messages from the parent window (Acadio)
window.addEventListener('message', function(event) {
if (event.data.action === 'init') {
console.log('Acadio Data Received', event.data);
// check if the activity is already completed
if (event.data.complete) {
console.log('Activity already completed');
setComplete();
}
}
});
// Toggle the submit button based on the checkbox state
function toggleSubmitButton() {
const checkbox = document.getElementById('ackCheckbox');
const submitBtn = document.getElementById('submitBtn');
submitBtn.disabled = !checkbox.checked;
}
// Set the submit button to complete state
function setComplete() {
const submitBtn = document.getElementById('submitBtn');
submitBtn.textContent = 'Complete';
submitBtn.style.backgroundColor = 'green';
const checkbox = document.getElementById('ackCheckbox');
checkbox.disabled = true;
checkbox.checked = true;
}
// Submit the acknowledgment form
function submitForm() {
// Use postMessage to mark the activity complete
// since this will be displayed in an iframe we use window.parent.postMessage
window.parent.postMessage({
target: 'acadio',
complete: true
}, "*");
// Set the submit button to complete state
setComplete();
}
</script>
</body>
</html>
An example of a form script that collects a signature and verification pin and returns completion data using the window.postMessage() method is below:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Acknowledgment Form</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.form-container {
max-width: 500px;
margin: auto;
border: 1px solid #ccc;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.form-group {
display: flex;
align-items: center;
margin-bottom: 15px;
}
.form-group label {
display: none; /* Hide labels since fields are on the same row */
}
#signature {
width: 80%;
margin-right: 10px;
}
#verification {
width: 20%;
}
input {
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
font-size: 16px;
}
#submitBtn {
background-color: grey;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: not-allowed;
font-size: 16px;
transition: background-color 0.3s ease, cursor 0.3s ease;
}
#submitBtn:enabled {
background-color: black;
cursor: pointer;
}
</style>
</head>
<body>
<div class="form-container">
<p>
Please complete the form below to acknowledge and verify your submission.
</p>
<form id="ackForm" onsubmit="submitForm(event)">
<div class="form-group">
<input type="text" id="signature" name="signature" placeholder="Type your signature" required>
<input type="text" id="verification" name="verification" placeholder="4-digit code" pattern="\d{4,4}" maxlength="4" required>
</div>
<button id="submitBtn" disabled>Submit</button>
</form>
</div>
<script>
// Data collection form
console.log('Data collection form initialized');
// Listen for messages from the parent window (Acadio)
window.addEventListener('message', function(event) {
if (event.data.action === 'init') {
console.log('Acadio Data Received', event.data);
// check if the activity is already completed
if (event.data.complete) {
console.log('Activity already completed');
setComplete();
}
// restore form data if available
if (event.data.data) {
const { signature, verification } = event.data.data;
if (signature) document.getElementById('signature').value = signature;
if (verification) document.getElementById('verification').value = verification;
}
}
});
// Enable submit button when all fields are filled and valid
const form = document.getElementById('ackForm');
const submitBtn = document.getElementById('submitBtn');
form.addEventListener('input', () => {
setNotComplete();
const isValid = form.checkValidity();
submitBtn.disabled = !isValid;
});
// Set the submit button to complete state
function setComplete() {
submitBtn.textContent = 'Completed';
submitBtn.style.backgroundColor = 'green';
submitBtn.disabled = true;
}
// set the submit button to not complete state
function setNotComplete() {
submitBtn.textContent = 'Submit';
submitBtn.style.backgroundColor = null;
}
// Submit the form
function submitForm(event) {
event.preventDefault(); // Prevent form from reloading the page
// Gather form data
const signature = document.getElementById('signature').value;
const verification = document.getElementById('verification').value;
// Send data via window.postMessage
const message = {
target: 'acadio',
complete: true,
action: 'storeActivityData',
data: {
signature: signature,
verification: verification,
lastUpdated: new Date().toISOString()
}
};
window.parent.postMessage(message, "*");
// Set the submit button to complete state
setComplete();
}
</script>
</body>
</html>
Enabling the Requires Completion Event setting
Follow the steps below to enable an external completion event on an activity:
- Click on the activity from the curriculum to edit it.
- Select Options from the drawer on the right of the screen.
- Switch the Requires Completion Event toggle on.
- Click Save.
Creating & embedding a code asset
After enabling the Requires Completion Event setting on an activity, the code asset must be created and embedded in an activity. This can be accomplished by using the Custom activity type or by embedding the code asset in another activity, such as a Book activity.
IMPORTANT: In both of the use cases above, it is strongly recommended that you use either the Embed with iFrame option or the Insert as a resizable window option to ensure that data is returned to Acadio. Depending on the code used, other embedding options may not consistently return the desired data.
Follow the steps below to create a code asset:
- Click the Asset Library button when in an activity's edit mode, or select Content>Assets from the main menu.
- Next, click the Create New tab at the top.
- Select Create Asset using Code and paste your code into the field.
- Click Preview to see the code-generated asset in the drawer.
- Enter a name for the new asset in the drawer.
- When finished, click Save. If creating a new code asset while editing an activity, select either the Embed with iFrame or Insert as resizable window option to embed it into the activity. Then, click Select.
Data collected by the embedded code asset is accessible while in the activity using the Student Status tab, found on the drawer on the right of the screen.