Meerkat

Meerkat

Advanced Reply Forms

This article assumes that you have read through the Reply Forms article and already have a custom reply form that you want to extend further with JavaScript.

You can hook into Meerkat's reply-to functionality by modifying the MeerkatReply window object. This object is simply a wrapper object that contains a number of functions that get called at various times during the comment reply process. It is important that any customized JavaScript code be loaded after Meerkat's{{ meekrat:replies-to }} tag.

#Object Properties

To make things as simple as possible, Meerkat provides you with some properties that you can use in your own form implementation:

#API Endpoints

The Endpoints static object contains the API endpoints that you can submit to from your site. The default endpoints are:

Endpoint Description
SubmitComment The API endpoint to POST comment replies to.

You might use the endpoints like so (the following example utilizes jQuery to make HTTP requests):

1MeerkatReply.submit = function (evt) {
2 // Collect the data.
3 var data = {};
4 
5 $.post(MeerkatReply.Endpoints.SubmitComment, data, function () {
6 // Implement the handler.
7 });
8 
9 evt.preventDefault();
10};

#Life Cycle Settings

The MeerkatReply object contains life-cycle settings that can be used to alter the behavior of the default comment reply process. The current exposed setting is the closeOnCancel setting.

By default, Meerkat will automatically remove the comment reply form when a user clicks on a "Cancel Reply" button. To disable this behavior and have the form remain open, you may adjust the setting like so:

1// Keep the reply form open.
2MeerkatReply.closeOnCancel = false;

#getOpenReplyForm Helper Method

The getOpenReplyForm will return the currently open form on your page:

1MeerkatReply.submit = function (evt) {
2 var currentForm = MeerkatReply.getOpenReplyForm();
3 
4 evt.preventDefault();
5};

#Event Methods

Meerkat will call various methods throughout the reply process. You can tap into these by supplying your own implementation for the submit, canceled, and replyOpen methods.

#submit Event Method

The sumbit() method is called when a visitor clicks on the "Submit Reply" button. This method is wired up to the form's submit event, so you can do anything you'd like here:

1MeerkatReply.submit = function (evt) {
2 // Handle the form.
3 console.log('The visitor clicked sumbit!');
4 
5 // Prevent the default submit behavior.
6 evt.preventDefault();
7};

#canceled Event Method

The canceled() method is called after a visitor has clicked the "Cancel Reply" link on your site. Meerkat will supply the ID of the comment that the visitor was replying to as well as an instance of the comment form:

1MeerkatReply.canceled = function (commentId, form) {
2 console.log('The visitor canceled their reply to: ' + commentId);
3 
4 // If you set `closeOnCancel` to `false`, we can do our own thing here.
5 $(form).fadeOut();
6};

#replyOpen Event Method

The replyOpen() method is called when the reply form is being presented to the user. If you previously hid the form for some reason, or would like to animate the appearance, you can do that here. You will receive an instance of the reply form as the only argument:

1MeerkatReply.replyOpen = function(form) {
2 // Show the form and fade in.
3 $(form).show().fadeIn();
4};

#Submitting Replies via AJAX

When customizing your comment form with the JavaScript API and helper methods, you might want to submit the comments to the Meerkat API via AJAX. In doing so, you can create incredibly interactive experiences for your site's visitors.

Before diving into the rest of the docs on this page, it is important to understand that the implementation details below are very opinionated; they are not the definitive way to implement Meerkat, or any AJAX based system for that matter. These docs will get you up and running, but don't feel like this is the "one true source"; feel free to innovate and experiment. If you come up with something amazing, feel free to share it!

The following is an example of a custom reply form using Bootstrap 3 (more examples and pre-made options to come at a later date):

1<div style="display:none;">
2 {{ meerkat:create data-meerkat-form="comment-reply-form" class="meerkat__reply--form" }}
3 <div class="row">
4 <div class="col-sm-12">
5 <div class="form-group">
6 <div class="col-xs-6">
7 <label for="name">Name</label>
8 <input class="form-control input-lg" type="text" id="name"
9 name="name" placeholder="Please enter your name. This will be public."
10 value="{{ old.name }}">
11 <p class="text-danger" data-validation-error></p>
12 </div>
13 <div class="col-xs-6">
14 <label for="email">Email</label>
15 <input class="form-control input-lg" type="email" id="email"
16 name="email" placeholder="Please enter your email. This remains private."
17 value="{{ old.email }}">
18 <p class="text-danger" data-validation-error></p>
19 </div>
20 </div>
21 </div>
22 </div>
23 <div class="row">
24 <div class="col-sm-12">
25 <div class="form-group">
26 <div class="col-xs-12">
27 <label for="comment">Comment</label>
28 <textarea class="form-control input-lg" id="comment" name="comment" rows="5"
29 placeholder="Enter your comment or feedback here (minimum of five characters)">{{ old.comment }}</textarea>
30 <p class="text-danger" data-validation-error></p>
31 </div>
32 </div>
33 </div>
34 </div>
35 <div class="form-group">
36 <div class="col-xs-12">
37 <button class="btn btn-primary" type="submit"><i class="fa fa-comment-o"></i> Submit Reply</button>
38 <a href="#" data-meerkat-form="cancel-reply">Cancel Reply</a>
39 </div>
40 </div>
41 {{ /meerkat:create }}
42</div>

The reply form was wrapped in a hidden <div /> so it wouldn't be visible to visitors unless they clicked the reply button on a comment. Also, the decision was made to add the following <p /> after each input element:

1<p class="text-danger" data-validation-error></p>

We will use these later when displaying validation error messages to the visitor.

#Where to Make AJAX Calls

Where to Make AJAX Calls When integrating AJAX in your Meerkat comment's section, you typically will make AJAX calls from the MeerkatReply.submit method. The following examples will use jQuery, but you can use whatever methods you like.

The general steps are as follows:

  • We need to retrieve the comment data to submit to the server;
  • Make the AJAX calls to the server;
  • Retrieve the results from the server;
  • Update the UI to indicate success or failure;
  • Add the new comment to the page, if desired.
1MeerkatReply.submit = function(evt) {
2 // Prevent the default submit.
3 evt.preventDefault();
4 
5 // Get a reference to the current form. We could
6 // use the `MeerkatReply.getOpenReplyForm();`
7 // helper method, but since we are using
8 // jQuery for this example, $(this)
9 // will also work to get the form
10 var replyForm = $(this);
11 
12 // Get the form data. We will iterate the serialized
13 // form data; then just create a new data object.
14 var data = {};
15 var commentData = $(this).serializeArray().map(function (x) {
16 data[x.name] = x.value;
17 });
18 
19 // Perform the AJAX call.
20 $.post(MeerkatReply.Endpoints.SubmitComment, data, function (e) {
21 // Check if the comment post was successfull.
22 if (e.success) {
23 // Great, everything worked. Let's hide the form.
24 // We will also use the fade out animation so
25 // the change isn't jarring to the visitor.
26 $(replyForm).fadeOut(150, function () {
27 replyForm.remove();
28 });
29 
30 // The `submission` property contains the new comment.
31 var comment = e.submission;
32 
33 // Do anything you'd like here.
34 } else {
35 // Something went wrong here; not related to data validation.
36 }
37 }).fail(function (xhr, status, error) {
38 // We will handle errors later.
39 });
40};

Great! We now have a nice place to make AJAX calls to the Meerkat server API. However, we still need to handle any errors that might visitors might encounter.

#Handling AJAX Errors

Meerkat will enforce the validation rules set on your comment form's blueprint, even when making AJAX calls to the server. When there are validation errors, we can catch these via the fail() jQuery method. The validation errors are returned by the server in a field named errors.

The errors data will consist of a multi-dimensional array, where the key is the name of the input field and the value is another array consisting of all the validation error messages.

The following example demonstrates how we might retrieve these error messages:

1MeerkatReply.submit = function(evt) {
2 // Prevent the default submit.
3 evt.preventDefault();
4 
5 // Get a reference to the current form. We could
6 // use the `MeerkatReply.getOpenReplyForm();`
7 // helper method, but since we are using
8 // jQuery for this example, $(this)
9 // will also work to get the form
10 var replyForm = $(this);
11 
12 // Get the form data. We will iterate the serialized
13 // form data; then just create a new data object.
14 var data = {};
15 var commentData = $(this).serializeArray().map(function (x) {
16 data[x.name] = x.value;
17 });
18 
19 // Perform the AJAX call.
20 $.post(MeerkatReply.Endpoints.SubmitComment, data, function (e) {
21 // Check if the comment post was successfull.
22 if (e.success) {
23 // Great, everything worked. Let's hide the form.
24 // We will also use the fade out animation so
25 // the change isn't jarring to the visitor.
26 $(replyForm).fadeOut(150, function () {
27 replyForm.remove();
28 });
29 
30 // The `submission` property contains the new comment.
31 var comment = e.submission;
32 
33 // Do anything you'd like here.
34 } else {
35 // Something went wrong here; not related to data validation.
36 }
37 }).fail(function (xhr, status, error) {
38 // Get the submission errors.
39 var errors = xhr.responseJSON.errors;
40 });
41};

The validation errors will now be available via the errors variable. Pretty neat! But, how should we display these errors to the visitor? The method to do this will change depending on your design's markup, the CSS framework (if any) used, and personal preference.

Having said that, the following would work using the Bootstrap 3 framework example from earlier:

1MeerkatReply.submit = function (evt) {
2 evt.preventDefault();
3 var data = {};
4 var commentData = $(this).serializeArray().map(function (x) {
5 data[x.name] = x.value;
6 });
7 
8 // Let's get a reference to our reply form. We need to get
9 // the last form returned by this selector since there
10 // is a hidden comment reply form hanging around :)
11 var replyForm = $(this);
12 
13 $.post(MeerkatReply.Endpoints.SubmitComment, data, function (e) {
14 // Check if everything was successfull.
15 if (e.success) {
16 // Great, everything worked. Let's close the form.
17 $(replyForm).fadeOut(150, function () {
18 replyForm.remove();
19 });
20 
21 // Get the new comment.
22 var template = $.tmpl($('#comment-template').html(), e.submission);
23 
24 // Add our rendered comment to the DOM.
25 $('[data-meerkat-comment="' + e.submission.parent_comment_id + '"].media-body').append(template).fadeIn();
26 $('[data-meerkat-form="comment-form"]').show();
27 } else {
28 // Something went wrong.
29 }
30 }).fail(function (xhr, status, error) {
31 // Get the submission errors.
32 var errors = xhr.responseJSON.errors;
33 
34 // Let's iterate the errors, and update the UI.
35 $.each(errors, function (key, value) {
36 // 1. Target the reply form and the input element.
37 // 2. Modify the DOM as required.
38 
39 var inputElement = $(replyForm).find(':input[name="' + key + '"]');
40 
41 if (typeof inputElement !== 'undefined' && inputElement !== null && inputElement.length > 0) {
42 inputElement = inputElement[0];
43 
44 // Find the closest form group and add the `has-error` class to it.
45 $(inputElement).closest('.form-group').addClass('has-error');
46 
47 // Update the <p /> element below any input element that has validation errors.
48 $(inputElement).closest('.form-group').find('[data-validation-error]').text(value[0]);
49 }
50 
51 });
52 });
53};

While it might look complicated, we are simply iterating each of the error messages returned by the server and looking for any inputs that match in our reply form. If we find a message, we add the has-error class to it's parent element that has the form-group class; after that we update the error message that is displayed to the visitor.

Some absolutely amazing
people

The following amazing people help support this site and my open source projects ♥️
If you're interesting in supporting my work and want to show up on this list, check out my GitHub Sponsors Profile.