Example Contact Event
config.json
{
"workflowApiVersion": "1.1",
"metaData": {
"icon": "images/icon.png",
"transactionKeys": {
"0": {
"from": "Event Property",
"to": "DE_Name.DE_Property"
}
}
},
"type": "Event",
"lang":{
"en-US": {
"name": "Event (Workflow API v1.1)",
"description": "An example event using workflow API v1.1 format.",
"selectCountry": "Select Country",
"enterFirstName": "Enter First Name",
"enterLastName": "Enter Last Name",
"enterFavoriteFood": "Enter Favorite Food",
"countryCodeLabel": "Country Code",
"firstNameLabel": "First Name",
"lastNameLabel": "Last Name",
"favoriteFoodLabel": "Favorite Food",
"selectTransactionKeyMapping": "Transaction Key"
}
},
"configurationArguments": {},
"filterExpressionEnabled": false,
"wizardSteps": [
{ "key": "selectCountry", "label": "selectCountry" },
{ "key": "enterFirstName", "label": "enterFirstName" },
{ "key": "enterLastName", "label": "enterLastName" },
{ "key": "enterFavoriteFood", "label": "enterFavoriteFood", "active": false },
{ "key": "selectTransactionKeyMapping", "label": "selectTransactionKeyMapping" }
],
"userInterfaces": {
"configModal": {
"url": "index.html"
},
"summary": [
{
"valuePath": "arguments.countryCode",
"label": "countryCodeLabel"
},
{
"valuePath": "arguments.firstName",
"label": "firstNameLabel"
},
{
"valuePath": "arguments.lastName",
"label": "lastNameLabel"
},
{
"valuePath": "arguments.favoriteFood",
"label": "favoriteFoodLabel"
},
{
"valuePath": "metaData.transactionKeys",
"label": "Transaction Key"
}
]
}
}index.html
Every custom event must have an index.html in the root of its endpoint.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Custom Event Test</title>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/require.js"></script>
<script type="text/javascript">
(function() {
var config = {
baseUrl: ''
};
var dependencies = [
'customEvent'
];
require(config, dependencies);
})();
</script>
<!--Styles-->
<style type="text/css">
body {
padding: 15px;
margin: 0;
}
h1 {
font-size: 16px;
}
.step {
display: none;
}
#step1 {
display: block;
}
</style>
</head>
<body>
<div id="step1" class="step">
<h1>Step 1: Country Code</h1>
<select id="select-country-code">
<option value="US">United States</option>
<option value="GB">United Kingdom</option>
<option value="BR">Brazil</option>
<option value="DE">Germany</option>
</select>
<br />
<button id="toggleLastStep">Toggle Favorite Food Step</button>
</div>
<div id="step2" class="step">
<h1>Step 2: First Name</h1>
<input id="select-first-name">
</div>
<div id="step3" class="step">
<h1>Step 3: Last Name</h1>
<input id="select-last-name">
</div>
<div id="step4" class="step">
<h1>Step 4: Favorite Food</h1>
<input id="select-favorite-food">
</div>
</body>
</html>customEvent.js
Postmonger is required for communication between Journey Builder and the custom event.
define([
'js/postmonger'
], function(
Postmonger
) {
'use strict';
var connection = new Postmonger.Session();
var payload = {};
var lastStepEnabled = false;
var steps = [ // initialize to the same value as what's set in config.json for consistency
{ "key": "selectCountry", "label": "selectCountry" },
{ "key": "enterFirstName", "label": "enterFirstName" },
{ "key": "enterLastName", "label": "enterLastName" },
{ "key": "enterFavoriteFood", "label": "enterFavoriteFood", "active": false }
];
var currentStep = steps[0].key;
$(window).ready(onRender);
connection.on('initEvent', initialize);
connection.on('requestedTokens', onGetTokens);
connection.on('requestedEndpoints', onGetEndpoints);
connection.on('clickedNext', onClickedNext);
connection.on('clickedBack', onClickedBack);
connection.on('gotoStep', onGotoStep);
function initialize (data) {
var countryCode;
var firstName;
var lastName;
if (data) {
payload = data;
}
if (payload['arguments']) {
countryCode = payload['arguments'].countryCode;
firstName = payload['arguments'].firstName;
lastName = payload['arguments'].lastName;
}
$('#select-country-code').val(countryCode);
$('#select-first-name').val(firstName);
$('#select-last-name').val(lastName);
}
function onGetTokens (tokens) {
// Response: tokens = { token: <legacy token>, fuel2token: <fuel api token> }
// console.log(tokens);
}
function onGetEndpoints (endpoints) {
// Response: endpoints = { restHost: <url> } i.e. "rest.s1.qa1.exacttarget.com"
// console.log(endpoints);
}
function onClickedNext () {
if ((currentStep.key === 'enterLastName' && steps[3].active === false) || currentStep.key === 'enterFavoriteFood') {
save();
} else {
connection.trigger('nextStep');
}
}
function onClickedBack () {
connection.trigger('prevStep');
}
function onGotoStep (step) {
showStep(step);
connection.trigger('ready');
}
function onRender() {
connection.trigger('ready'); // JB will respond the first time 'ready' is called with 'initEvent'
connection.trigger('requestTokens');
connection.trigger('requestEndpoints');
$('#toggleLastStep').click(function() {
lastStepEnabled = !lastStepEnabled; // toggle status
steps[3].active = !steps[3].active; // toggle active
connection.trigger('updateSteps', steps);
});
}
function showStep(step, stepIndex) {
if (stepIndex && !step) {
step = steps[stepIndex-1];
}
currentStep = step;
$('.step').hide();
switch(currentStep.key) {
case 'selectCountry':
$('#step1').show();
break;
case 'enterFirstName':
$('#step2').show();
$('#step2 input').focus();
break;
case 'enterLastName':
$('#step3').show();
$('#step3 input').focus();
break;
case 'enterFavoriteFood':
$('#step4').show();
$('#step4 input').focus();
break;
}
}
function save() {
var countryCode = $('#select-country-code').find('option:selected').attr('value');
var firstName = $('#select-first-name').val();
var lastName = $('#select-last-name').val();
var favoriteFood = $('#select-favorite-food').val();
payload['arguments'] = payload['arguments'] || {};
payload['arguments'].countryCode = countryCode;
payload['arguments'].firstName = firstName;
payload['arguments'].lastName = lastName;
// Example criteria - if 'filterExpressionEnabled' is set to true in config.json, Journey Builder will
// populate this step with the 'criteria' XML passed here
// payload['arguments'].criteria = "<FilterDefinition Source='SubscriberAttribute'><ConditionSet Operator='AND' ConditionSetName='Grouping'><Condition ID='13D65BB5-1F98-E411-9D68-00237D5401CE' isParam='false' Operator='Equal' operatorEditable='0' valueEditable='1' annotation=''><Value><![CDATA[" + countryCode + "]]></Value></Condition><Condition ID='0CD65BB5-1F98-E411-9D68-00237D5401CE' isParam='false' Operator='Equal' operatorEditable='0' valueEditable='1' annotation=''><Value><![CDATA[" + firstName + "]]></Value></Condition><Condition ID='12D65BB5-1F98-E411-9D68-00237D5401CE' isParam='false' Operator='Equal' operatorEditable='0' valueEditable='1' annotation=''><Value><![CDATA[" + lastName + "]]></Value></Condition></ConditionSet></FilterDefinition>";
if (favoriteFood && steps[3].active) {
payload['arguments'].favoriteFood = favoriteFood;
}
payload['metaData'] = payload['metaData'] || {};
payload['configurationArguments'] = payload['configurationArguments'] || {};
payload.dataExtensionId = '<data extension ID>';
connection.trigger('updateEvent', payload);
}
});