Scratchpad - Demonstration AJAX Add-on

Kier

XenForo developer
Staff member
This add-on is intended to be a demonstration of how to work with AJAX form submission data and return HTML that can be inserted into your page without a refresh.

It takes the form of a very simple textbox into which notes can be entered, then when submitted, they appear in a list of recent notes below.

The add-on makes use of XenForo.AutoValidator to facilitate the form submission, then uses custom code in the controller and the view layer to return template HTML and additional data.

This video accompanies the add-on, and explains what is going on:

To view this content we will need your consent to set third party cookies.
For more detailed information, see our cookies page.
http://vimeo.com/17132298Or view on Vimeo

To install the add-on, decompress the zip then upload the contents of the upload directory (which should contain js/scratchpad and library/Scratchpad) and finally install the addon_Scratchpad.xml via the XenForo Add-on Installer system.
 

Attachments

Would you look at that... it worked! Wonderful as always Kier... I tell ya, its really nice to get this kind of interaction with the developers. I can tell that XenForo is going to have a burgeoning mod community because of it...

This is my new code: only the relevant bits of course...
Code:
public function actionMediaPost()
{
	$this->_assertPostOnly();

	$mediaParts = explode('.', $this->slugs[0]);
	$mediaID = end($mediaParts);

	if (!$media = $this->getModelFromCache('EWRmedio_Model_Media')->getMediaByID($mediaID))
	{
		return $this->responseRedirect(XenForo_ControllerResponse_Redirect::SUCCESS, 'media');
	}

	$input['username'] = $this->_input->filterSingle('username', XenForo_Input::STRING);
	$input['message'] = $this->getHelper('Editor')->getMessageText('message', $this->_input);
	$this->getModelFromCache('EWRmedio_Model_Comments')->postComment($input, $media);

	if ($this->_noRedirect())
	{
		return $this->actionMediaComments();
	}

	return $this->responseRedirect(XenForo_ControllerResponse_Redirect::SUCCESS,XenForo_Link::buildPublicLink('full:media', $media));
}
Code:
<?php

class EWRmedio_ViewPublic_MediaComments extends XenForo_ViewPublic_Base
{
	public function renderJson()
	{
		$output = $this->_renderer->getDefaultOutputArray(get_class($this), $this->_params, $this->_templateName);
		$output['status'] = new XenForo_Phrase('your_comment_has_been_posted');
		return XenForo_ViewRenderer_Json::jsonEncodeForOutput($output);
	}
}
Code:
XenForo.CommentPoster = function($form)
{
	$form.bind('AutoValidationBeforeSubmit', function(e)
	{
		XenForo.MultiSubmitFix($form);
	});

	$form.bind('AutoValidationComplete', function(e)
	{
		if (e.ajaxData.status)
		{
			$form.find('textarea[name=message]').val('').blur();

			$('#CommentStatus').text(e.ajaxData.status);
			setTimeout(function() { $('#CommentStatus').text(''); }, 4000);
		}

		if (e.ajaxData.templateHtml)
		{
			e.preventDefault();

			new XenForo.ExtLoader(e.ajaxData, function()
			{
				$(e.ajaxData.templateHtml).xfInsert('replaceAll', '#mediaComments', 'xfShow');
			});
		}
	});
}
 
Couple of notes...

You have the following line in your scratchpad.js
Code:
	// re-enable the submit button if it's been disabled
	$form.find('input:submit').removeAttr('disabled').removeClass('disabled');
I don't see the use for this. Instead of manually disabling the submit button, I am using your built in
"XenForo.MultiSubmitFix()" function, as it looks like it does all this automatically. It disables the submit button for 4 seconds the moment its clicked. I like this because it prevents double/triple posting.

The next thing is that I decided NOT to use the "e.preventDefault()" function in my newest code. You say in your code that it prevents the Redirect Processing... but I don't think it does that. Even when I remove this function, it still prevents the redirect processing, probably because I am now returning a ResponseView, instead of a ResponseRedirect. So in essence this function's purpose should have nothing to do with that when it comes to FORMS. I understand it does work like this when you're replacing simple <A> tags, but for forms, it seems useless.

Instead, it looks like the only thing it does for forms is disable the popdown error/success messages that show up when you make a post. I rather like these messages and I wish to keep them in. So I have taken the preventDefault function out. Are there any other negatives to doing this that I should be aware of? (yes, I ended my sentence with a preposition... but I'm American, its what we do!)

Also, right now the popdown message is saying "Unspecified Error"... how do I edit this?
 
Looks good. Only one comment:
PHP:
if ($this->_noRedirect())
{
	return $this->actionMediaComments(); 
}
Should probably be
PHP:
if ($this->_noRedirect())
{
	return $this->responseReroute(__CLASS__, 'media-comments');
}
As this will allow your own code to be extended in due course :)
 
When install xml file:
Server Error

Mysqli statement execute error : Table 'scratchpad_note' already exists
  1. [*]Zend_Db_Statement_Mysqli->_execute() in Zend/Db/Statement.php at line 312
    [*]Zend_Db_Statement->execute() in Zend/Db/Adapter/Abstract.php at line 468
    [*]Zend_Db_Adapter_Abstract->query() in Scratchpad/Install/Base.php at line 15
    [*]Scratchpad_Install_Base::install()
    [*]call_user_func() in XenForo/Model/AddOn.php at line 204
    [*]XenForo_Model_AddOn->installAddOnXml() in XenForo/Model/AddOn.php at line 159
    [*]XenForo_Model_AddOn->installAddOnXmlFromFile() in XenForo/ControllerAdmin/AddOn.php at line 180
    [*]XenForo_ControllerAdmin_AddOn->actionInstall() in XenForo/FrontController.php at line 303
    [*]XenForo_FrontController->dispatch() in XenForo/FrontController.php at line 132
    [*]XenForo_FrontController->run() in /home/xxxxxxx/public_html/forum/admin.php at line 13
 
Don't you mean?
Code:
return $this->responseReroute(__CLASS__, 'MediaComments');

Also... I just edited my last post with a question:
right now the popdown message is saying "Unspecified Error"... how do I edit this?
 
The addon's install file seems to have an unnecessary event listener. Removing that, I was able to install and test the addon successfully. Also, in /Scratchpad/Model/Node.php (Line 45); you should call the max() function:
PHP:
		// ensure we have a meaningful value for $maxNotes
		if ($maxNotes = max($maxNotes, 0))
		{


Thanks for the demo! :)
 
You have the following line in your scratchpad.js
Code:
	// re-enable the submit button if it's been disabled
	$form.find('input:submit').removeAttr('disabled').removeClass('disabled');
I don't see the use for this. Instead of manually disabling the submit button, I am using your built in
"XenForo.MultiSubmitFix()" function, as it looks like it does all this automatically. It disables the submit button for 4 seconds the moment its clicked. I like this because it prevents double/triple posting.
I manually re-enable the button because it's done after the textarea is cleared, and after the AJAX request has returned - so it's fine to allow things to resume immediately.
 
The addon's install file seems to have an unnecessary event listener. Removing that, I was able to install and test the addon successfully. Also, in /Scratchpad/Model/Node.php (Line 45); you should call the max() function:
PHP:
		// ensure we have a meaningful value for $maxNotes
		if ($maxNotes = max($maxNotes, 0))
		{


Thanks for the demo! :)
Yes, you're right - I'll update the zip in a moment.
 
The next thing is that I decided NOT to use the "e.preventDefault()" function in my newest code. You say in your code that it prevents the Redirect Processing... but I don't think it does that.
No, it doesn't affect the PHP at all. It simply prevents the XenForo.AutoValidator Javascript function from continuing and posting the normal success message. See xenforo.js line 5199:
Code:
if (eComplete.isDefaultPrevented())
{
	return false;
}
 
I'm getting an odd inspector response...

Unable to request validation for field "message" due to lack of fieldValidatorUrl in form tag.
Abort pending field validation...
XHR finished loading: "http://xen1.8wayrun.com/media/nicovideo-test-video.6/post".
Event: AutoValidationDataReceived
message: Okay
Event: AutoValidationComplete

Code:
    <form action="{xen:link 'full:media/post', $media}" method="post" style="margin: 0px;" class="messageSimple primaryContent AutoValidator" id="CommentPoster">
        <xen:avatar user="$visitor" size="s" />
        <div class="messageInfo">
            <xen:if is="!{$visitor.user_id}"><input type="text" name="username" class="textCtrl" placeholder="{xen:phrase guest}..." /></xen:if>
            <textarea name="message" class="textCtrl Elastic" placeholder="{xen:phrase post_comment}..." rows="3" cols="50"></textarea>
            <div style="margin-top: 8px; float: left;" id="CommentStatus"></div>
            <div class="submitUnit">
                <input type="hidden" name="_xfToken" value="{$visitor.csrf_token_page}" />
                <input type="submit" class="button primary" value="{xen:phrase post}" accesskey="s" />
            </div>
        </div>
    </form>
 
It's an expected notice - you only need to be concerned if you to do want before-submission validation, like we have on the homepage field when you edit your personal details.
 
It's an expected notice - you only need to be concerned if you to do want before-submission validation, like we have on the homepage field when you edit your personal details.
Is there any way to fix it? I dont like errors and warnings...
 
Code updated to resolve the oopsies spotted by Shadab.

Now at version 0.2.
 
This was to be the subject of another video, but I'll lay out the basics here.

XenForo.AutoValidator is a multi-purpose class. It does the following:
  1. Submits the form data via AJAX
  2. Receives back the AJAX response and determines if it is valid, and shows an appropriate set of errors if it's not
  3. Submits individual fields for validation before form submission, and displays inline errors if they do not validate.
The first two parts are automatic, and happen simply by identifying a form as class="AutoValidator".

The third part requires the use of a field validator action. This can be identified using data-fieldValidatorUrl="{xen:link prefix/validator-action}" in the form tag.

An example field validator controller action might look like this:
PHP:
public function actionValidateField()
{
	$this->_assertPostOnly();

	$field = $this->_getFieldValidationInputParams();

	return $this->_validateField('XenForo_DataWriter_User', array(
		'name' => $field['name'],
		'existingDataKey' => $this->_input->filterSingle('user_id', XenForo_Input::UINT)
	));
}
It is possible to have the form act as an opt-in field validator, in which all fields are ignored unless they specifically include class="OptIn", or to have it as an opt-out system, in which all fields are included in the validation unless they include class="OptOut".

Hope that goes some of the way to answering your question :)
 
Back
Top Bottom