Drupal 8 as a Static Site: Drupal 8 Contact Form Thank You Page

Submitted by nigel on Saturday 4th May 2019
Architecture

Our previous two tutorials on the Drupal 8 as a static site covered the Contact Form and the journey through the action to AWS Lambda to process the form and send an email. Now the final part of the contact form journey - returning back to the static site and showing a Thank You page. 

In fact in this tutorial the Thank You path will actually be the same path with the contact form on it - so we return to the starting point, but we want to show a message back to the user to thank them for filling out the form. The notification back to the user will have to be JavaScript obviously since we have no backend language functionality.

If you remember the redirect back to the static site from AWS uses a HTTP code of 307. This code matches in the incoming HTTP request with the redirect. So since in our case the form was POSTed, then the redirect will also be POSTed back to the static site. This is both a blessing and a curse as we'll see. 

Common wisdom says that JavaScript can neither detect whether an incoming request is POSTed or GETed, nor retrieve any of the POSTed data. That is theoretically true, but there are always workarounds of course :) :) 

Adding the JavaScript
This is very similar to our earlier tutorial on how to add the Elasticsearch JavaScript client. So I won't dwell too much on this. Firstly we need to extend our template_preprocess_page function to add our thank-you JS library. This is the second section of code below, underneath the elasticsearch part

{themename}.theme - in my case the custom theme is called beezee8.
<?php
function beezee8_preprocess_page(&$variables) {

    
// If we are on the search page, load the JS search client api
    // and our implementation to Elasticsearch
    
if (\Drupal::routeMatch()->getRouteName() == 'search.view_node_search') {
        
$variables['#attached']['library'][] = 'beezee8/elastic-library';
    }

    
// If we are on the contact form page, load the JS to show thank you message
    
if (\Drupal::request()->getRequestUri() == '/about') {
        
$variables['#attached']['library'][] = 'beezee8/thank-you-library';
   }
}
?>
In the code above I get the current path alias and should that equal the '/about' page then I inject my JS library which is defined below.
Libraries file
The libraries file now needs a further entry for our thank you JS. Again we already created an entry for elasticsearch so I am not going to go over this in too much detail.

{themename}.libraries.yml
global-styling:
  css:
    theme:
      css/style.css: {}
elastic-library:
  js:
    js/elasticsearch-js/elasticsearch.min.js: {}
    js/beezee/beezee_elastic.js: {}
thank-you-library:
  js:
    js/beezee/beezee_thankyou.js: {}
JavaScript Thank You
Now here's the JavaScript. I did say that there is no way of knowing whether the HTTP request is GET or POST - well true, but we can deduce it. If we interrogate the referrer and it equals the current URL then we can make the assumption that the form has been POSTed, completed its round trip to AWS Lambda and back with a 307 code, and therefore we should show the thank you message. If you have a look at my code below you will see the conditional, and you will see the markup I inject into the page - it's classic Drupal 8 Bootstrap since that's how my theme is built. Your mileage here will obviously vary dependent upon your own theme.

{themename}_thankyou.js
(function ($, Drupal) {
 
    var thank_once;
 
    function BeezeeThankyou() {
        if (!thank_once) {
            thank_once = true;
 
            // If we are arriving here from lambda which passes on the referrer from here
            // then the form has been POSTed so show the thank you page
            if (document.referrer == document.URL) {
 
                // Markup to add the thankyou message
                var thanks = [
                    '<div class="alert alert-success alert-dismissible" role="alert">',
                    '<button role="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>',
                    '<h4 class="sr-only">Status message</h4>',
                    'Thank you for contacting me. I will be in touch.',
                    '</div>'
                ];
 
                // Inject the markup
                $('.region-highlighted').append(thanks.join(''));
            }
        }
    }
 
    Drupal.behaviors.beezee_thankyou = {
        attach: function (context, settings) {
            BeezeeThankyou();
        }
    };
})(jQuery, Drupal);
nginx Server Configuration
nginx error
If we try our form now (or at least if I do since I'm using nginx) - we will get an nginx 405 Not Allowed error. Remember I said the POST could be a blessing and a curse? The error is because by default nginx will not allow a POST to a static page. Thankfully there is a workaround. Locate the server configuration for your particular virtual host, and edit it by adding the following line into the server section.

{VM name}.conf
server {
.
.
.
      error_page  405     =200 $uri;
.
.
Form submission
form submission

Ok we should now be good to go. Submit the form and it should do the round trip from static site to AWS Lambda back to static site and an email arriving in your inbox! 

An even better solution?
alternative solution

If you look carefully above you will see a placeholder in the thank you message. So am I saying it is possible to retrieve the POSTed data and insert the name into the placeholder? Sort of. There is a JS library called jQuery-PostCapture which can achieve this. It works by capturing the POSTed data when the form is initially submitted. This copy of the data is stored either as a cookie or in the browser's local storage. Once the trip to AWS Lambda is completed, this data can be fetched from the cookie or local storage - so the data isn't fetched from the actual POST itself. 

The problem I've got with this is neither a cookie nor local storage is secure. However if you feel that the gains (being able to customise a message on the thank you page) is worth the security risk, then give it a shot!