We’ve migrated our documentation to a new site, which means some URLs have changed.
Subscriptions

How to Create a Newsletter Signup with Templates

Unlock the full potential of our feature and take your skills to the next level! Dive into our Training Center and discover exclusive Best Practice resources that will elevate your implementation strategy. With expert tips and insider knowledge, you'll become a master in no time. Access the links below to learn more and gain a competitive edge.

Ready to get started? Our Training Center is just a click away: here.

*For more information about our Training center, please visit the article here.

This guide includes:

In addition to the above, clients occasionally want to store data collected from a Piano template as a cookie and segment their audiences based off that cookie's values, which is why this guide also includes:

Custom Event, Ng-Model, and Form Model Basics

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 specified 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 newsletter sign-up, the ng-model directive allows you to bind the value of your email 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, where you can pass it either to your own back-end or directly to a newsletter service provider.

Keep in mind that some popular newsletter services, such as SailThru, only allow for server-to-server communication. In such cases you'll need to pass the data from your front-end to your back-end before sending it to your newsletter provider's back-end. If you're using SailThru, here is the API endpoint you'll likely want to use.

Example Form HTML Within a Piano Template

The basic example HTML below shows how a newsletter sign-up form might look within a Piano offer template. It includes just one input field and and an error message:

HTML
<div style="height: 5em">\n    <!--The ng-model directive is first used in the input field-->\n    <!--to bind the email information to the example variable "newsletterEmail".-->\n    <input type="text" ng-model="newsletterEmail" placeholder="Your e-mail address" name="text">\n    <!--The "external-event" directive then captures the sign-up event -->\n    <!--and the "external-event-email" directive captures the "newsletterEmail" value.-->\n    <!--We're also passing the "params" object so we can communicate back to the iframe in case of an error.-->\n    <input type="submit" external-event="email-signup" external-event-email="{{newsletterEmail}}" value="Subscribe" external-event-params="{{params}}">\n\n    <!--This block is an example of displaying an error message inside the template. By default it's hidden.-->\n    <div id="error-message-wrapper" style="display: none">\n        <span id="error-message"></span>\n        <a href="javascript:void(0)" id="close-error-btn">Close</a>\n    </div>\n</div>

Though the above form only captures a single input field (an email address), you can capture as many input fields as you like using this process. You should also feel free to add whatever additional styling, messaging, and logic you desire to the example code above.

As noted in the inline comments, this example includes Piano's params object, which contains the ID for the Piano template iframe along with other contextual information about the template. That ID is necessary for passing data back to the iframe, a functionality that's important for receiving the success and error messages we'll discuss in more detail later in this guide.

Note: Because Piano's templates use version 1.2.22 of Angular JS, the accepted input types will be limited to the inputs listed here. If you have a problem with one of the accepted input types, try an alternate input type. For instance, the example above uses "text" rather than "email" in the input field, but either should work.

Example Front-end JavaScript for Collecting Form Data

After you've configured your Piano offer template, you'll need to add a JavaScript handler to your own front-end JavaScript to listen for the template's events. Here is a handler based on the example HTML we created above:

tp = window.tp || [];\n\ntp.push(["addHandler", "customEvent", function(event, b, c, d) {\n    switch (event.eventName) {\n        case 'email-signup':\n            var email = '';\n            var params;\n            var iframeId;\n\n            // We are parsing the params object sent from the template to find out which iframe triggered it\n            params = JSON.parse(event.params.params);\n            // And here's the iframeId we're looking for\n            iframeId = params.iframeId;\n\n            if ((typeof event.params.email != 'undefined') && (event.params.email.length > 0)) {\n                email = event.params.email;\n            }\n\n            // Here you'll need to pass the relevant data to your newsletter vendor or any other third-party system\n\n            // Additionally, we can check the response from the vendor.\n            var emailIsInvalid = false;\n            if (!emailIsInvalid) {\n                sendPostMessageToPiano(iframeId, false, 'You have entered an invalid email', 'email');\n            } else {\n                // If the email was added successfully set a cookie for Composer tracking.\n                pianoSetCustomVariableCookie('newsletter', 'true');\n                //We can close the offer now.\n                tp.offer.close();\n            }\n\n            break;\n    }\n}]);

Object values for custom events are accessed by parsing the event like this: event.params. With our example above, that means data from the external-event-email directive in the template is available via event.params.email in the JavaScript. If we'd instead had external-event-newsletter in the template, the corresponding JavaScript would be event.params.newsletter. You can use as many directives as needed to parse the information from your form.

Also notice in the example above that event.eventName includes a case for 'email-signup', which matches the name of the parameter in the example template's external-event code. It's this shared name that connects the custom event within the template to the JavaScript handler.

A few other JavaScript functions you should be aware of when constructing your front-end JavaScript:

  • pianoSetCustomVariableCookie: Used to set a Piano custom variable cookie for later use

  • pianoReadCustomVariableCookie: Used to read a Piano custom variable cookie

  • sendPostMessageToPiano: Used for sending data upstream to a Piano template

Piano's custom event framework uses JavaScript post messages, which Piano automatically parses. That means you can simply follow the above steps rather than manually sending post message data from Piano's template to your front-end JavaScript.

Important: Note that, as stipulated in the example code above, you'll need to determine how to best to pass your data to your newsletter provider (or any other third-party system you may be communicating with). For more information on how the data should be passed, you'll want to consult the API documentation of your newsletter vendor.

Example JavaScript Within a Piano Template for Success/Error Messages

Because we included the params object in the template HTML and parsed it in the front-end JavaScript, we have access to our template's iframe ID value. That ID allows for communication back to the template and for you to message users based on whether or not your form data was successfully sent to your newsletter provider.

Continuing with the above example, here is some JavaScript that can be placed within your Piano template (along with your form HTML) to listen for success/error messages sent from your front-end JavaScript. Also included in this example is some basic functionality for handling an error message:

HTML
<div custom-script>\n    // This is a simple listener for clicking on the close button in the error message.\n    $('#close-error-btn').click(function () {\n        $('#error-message-wrapper').hide();\n    });\n\n    // This is the listener that will receive the post message from your front-end JS in case of an error.\n    window.addEventListener("message", function (e) {\n        if (typeof e.data.piano != 'undefined') {\n            var result = e.data.piano;\n\n            if (!result.success) {\n                $('#error-message-wrapper').show();\n                $('#error-message').text(result.message);\n            }\n        }\n        return;\n    }, false);\n</div>

Note that this example includes the custom-script tag, which should be used anytime you want to add custom JavaScript to a Piano template.

Any user data you want stored permanently should be sent to your user database using the process we've outlined above. For user data that doesn't need to be stored longterm, some Piano clients choose instead to set a cookie with custom variables to track users who've made a specific selection on a form or taken some other action.

Below is some example JavaScript that can be added to your front-end (along with the form collection JS) to set a cookie:

function sendPostMessageToPiano(iframeId, success, message, object) {\n    var iframe = jQuery('#' + iframeId);\n\n    if (iframe.length) {\n        iframe[0].contentWindow.postMessage({\n            piano: {\n                success: success,\n                message: message,\n                object: object\n            }\n        }, '*');\n    }\n}\n\nfunction pianoSetCustomVariableCookie(name, value) {\n    var cookieValue = pianoReadCustomVariableCookie();\n    cookieValue[name] = value;\n\n    var d = new Date();\n    d.setTime(d.getTime() + (94608000000));\n    var expires = "expires=" + d.toUTCString();\n\n    document.cookie = "__pcvc=" + JSON.stringify(cookieValue) + ";" + expires + ";path=/";\n}

Along with the front-end JavaScript used for form collection and for setting a cookie, you'll want to add additional front-end JavaScript to read the custom variable values of that cookie. Here's some example JavaScript for reading the cookie values and setting the associated custom variables so Composer can segment based on them:

function pianoReadCustomVariableCookie(specificName) {\n    var cookieValue;\n    try {\n        var match = document.cookie.match(new RegExp('(^| )__pcvc=([^;]+)'));\n        if (match) {\n            cookieValue = JSON.parse(match[2]);\n        }\n    }\n    catch (e) {\n        cookieValue = {};\n    }\n    if (!cookieValue) {\n        cookieValue = {};\n    }\n    if (typeof specificName != "undefined") {\n        if (typeof cookieValue[specificName] != "undefined") {\n            return cookieValue[specificName];\n        }\n        return null;\n    }\n    return cookieValue;\n}\n\n// Read all values from cookie\nvar cookieValues = pianoReadCustomVariableCookie();\n\nfor (var i in cookieValues) {\n    // Set custom variables from cookie\n    tp.push(['setCustomVariable', i, cookieValues[i]]);\n}

After you've added this JavaScript to your website, you'll want to add the names and values of these custom variables to Composer's User Segmentation card in order to target users based off them.

Last updated: