Custom Event, Ng-Model, and Form Model Basic
Custom events are a neat and quick way of sending data gathered inside a Piano template to the parent window of your website for processing. The customEvent callback is used to track specific custom events. When editing an offer template, any element with an external-event directive will trigger a customEvent callback when the associated element is clicked on or otherwise activated. In addition to sending information about the custom event itself, you can send any additional data you like by using the external-event-params formulation.
The form model is a default Angular functionality. The ng-model directive lets you specify what belongs within that model. In the case of a user registration, the ng-model directive allows you to bind the value of your username and password input field as a variable within the form model. The customEvent callback then allows you to send the value of that variable to your front-end.
Example Template
<div style="height: 5em">
<input type="text" ng-model="username" placeholder="Username" name="text">
<input type="text" ng-model="password" placeholder="Password" name="text">
<input type="submit" value="Subscribe"
external-event="register"
external-event-username="{{username}}"
external-event-password="{{password}}"
external-event-params="{{params}}"
>
<div id="error-message-wrapper" style="display: none">
<span id="error-message"></span>
<a href="javascript:void(0)" id="close-error-btn">Close</a>
</div>
</div>
Example Front-end Javascript
tp.push(["addHandler", "customEvent", function(event, b, c, d) {
switch (event.eventName) {
case 'register':
var username = event.params.username;
var password = event.params.password;
var params;
var iframeId;
// We are parsing the params object sent from the template to find out which iframe triggered it
params = JSON.parse(event.params.params);
// And here's the iframeId we're looking for incase we need to send a message back about invalid data
iframeId = params.iframeId;
...
Life-Cycle of Data Collection
-
An external event is tied to your HTML submit button, and used in the case statement to determine what happens with the information once it is available to your front-end JS.
-
The ng-model is used to bind the input submitted by the user to a variable (e.g. username). The username value is passed via the external-event and becomes available inside JS via
event.params.username. -
The ng-model is used to bind the input submitted by the user to a variable (password). The password value is passed via external-event and becomes available inside JS via
event.params.password. -
The external event also passes
{{params}}, which can be used later for sending error messages back to the iFrame.
Utilizing the Data
Now that your front-end has access to these input values from the user, you can synchronize easily across systems. Often publishers want to send user information to their database, store it, and then send it back to Piano as a UserRef token. This could be accomplished with the use of AJAX and UserRef token generation, described here.
As long as you have the params object available, you’re able to restart the checkout process using tp.offer.startCheckout(params). Furthermore, if params.termId has been set, you can open the checkout backup and skip term selection all together. This could be useful in a situation where the user selects what term they want prior to UserRef token generation. You’re able to restart the checkout process and take the user straight to the entry form for payment information.
Error Messaging
You are also able to send a message back to the iFrame if needed. For example, you may have a user trying to register who already exists in your database. You could use the error messaging functionality to inform the user.
This is the function that you would use in order to send a message:
/**
* Function to send data upstream to Piano template
* @param iframeId - Element id of the Piano iframe
* @param success - true/false. Status of the message
* @param message - Error message text
* @param object - Additional data, like the the field that triggered the error
*/
function sendPostMessageToPiano(iframeId, success, message, object) {
var iframe = jQuery('#' + iframeId);
if (iframe.length) {
iframe[0].contentWindow.postMessage({
piano: {
success: success,
message: message,
object: object
}
}, '*');
}
}
Our example from earlier saved the iFrame’s params, so passing a message back to the user is possible. Here is what that would look like:
tp.push(["addHandler", "customEvent", function(event, b, c, d) {
switch (event.eventName) {
case 'register':
var username = event.params.username;
var password = event.params.password;
var params;
var iframeId;
// We are parsing the params object sent from the template to find out which iframe triggered it
params = JSON.parse(event.params.params);
// And here's the iframeId we're looking for incase we need to send a message back about invalid data
iframeId = params.iframeId;
//Here's where you'll be able to pass the data anywhere you need it, whether that's back to
//your database and then to us inside a UserREf token, to a third party service, or simply
//to your database. In this instance we're just logging it to the console.
console.log(username)
console.log(password)
console.log(params)
//With the iFrameID saved above, we have the option to send a message back to the window
//where the user entered the data. For example, after sending the user's information back to
//your database, you may find the user already has an account. In that case, you can use the
//sendPostMessageToPiano() function to display an error letting the user know
sendPostMessageToPiano(iframeId, false, 'You have entered a username already in use', 'username');
break;
}
}]);
Right now it’s passing a static message, but you may implement whatever logic and messaging that you need based on what happens during authentication in your database.
The final step is to add a <div custom-script> tag and container to your template, so that the template can listen for and display the error.
<div id="error-message-wrapper" style="display: none">
<span id="error-message"></span>
<a href="javascript:void(0)" id="close-error-btn">Close</a>
</div>
</div>
<div custom-script>
// This is a simple listener for clicking on the close button in the error message.
$('#close-error-btn').click(function () {
$('#error-message-wrapper').hide();
});
// This is the listener that will receive the post message from your front-end JS in case of an error.
window.addEventListener("message", function (e) {
// We verify that the error message is coming from Piano, so it must be what we're looking for.
if (typeof e.data.piano != 'undefined') {
// Get the object with the result.
var result = e.data.piano;
// We know how this object should be structured, so we're checking for the "success" field.
// We're expecting it to be false, so we can show an error message.
if (!result.success) {
// Show the error block.
$('#error-message-wrapper').show();
// Append the text message into the block.
$('#error-message').text(result.message);
}
}
return;
}, false);
</div>