XenForo AJAX Tutorial

Jaxel

Well-known member
Okay, that's what I thought you were doing. How about not doing that separate AJAX call at all, and having the necessary templates etc. to refresh your comment list (or just the latest comments) be returned from the same request that submits the form data? Having that extra XenForo.ajax() call is rather wasteful of resources. I've got to take the kids to nursery now, but I'll embellish some details when I return unless you've already worked it out. :)
I'm not exactly sure how I would do that...

Why is it a waste of resources? The queries will be going either way, wont they?

Below is the code for my comment switcher, and the comment poster
Code:
	public function actionMediaComments()
	{
		$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');
		}

		$options = XenForo_Application::get('options');
		$start = $this->_input->filterSingle('page', XenForo_Input::UINT) < 1 ? 1 : $this->_input->filterSingle('page', XenForo_Input::UINT);
		$stop = $options->EWRmedio_commentcount;

		$viewParams = array(
			'perms' => $this->perms,
			'start' => $start,
			'stop' => $stop,
			'media' => $media,
			'count' => $this->getModelFromCache('EWRmedio_Model_Comments')->getCommentCount($media),
			'comments' => $this->getModelFromCache('EWRmedio_Model_Comments')->getComments($media, $start, $stop),
		);

		return $this->responseView('EWRmedio_ViewPublic_MediaComments', 'EWRmedio_MediaComments', $viewParams);
	}

	public function actionMediaPost()
	{
		$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');
		}

		if ($this->_request->isPost())
		{
			$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);
		}

		return $this->responseRedirect(
			XenForo_ControllerResponse_Redirect::SUCCESS,
			XenForo_Link::buildPublicLink('full:media', $media),
			null,
			array(
				'newurl' => XenForo_Link::buildPublicLink('full:media/comments', $media),
				'status' => new XenForo_Phrase('your_comment_has_been_posted')
				)
		);
	}
 

Kier

XenForo developer
Staff member
Okay, let's take a look here Jason...

First thing to do is to update your Javascript. We don't want that second AJAX call, it's a big waste of resources to make that second connection, so let's alter the Javascript to expect the templateHtml to be returned by the first AJAX request:
Code:
// updates comment list after validation
$form.bind('AutoValidationComplete', function(e)
{
    // blurs focus away from submit button, dont see purpose of this line
    $form.find('input:submit').blur();

    // sets contents of a "status" DIV in template, removes status notice after 4 seconds
    if (e.ajaxData.status)
    {
        $('#CommentStatus').text(e.ajaxData.status);
        setTimeout(function() { $('#CommentStatus').text(''); }, 4000);
    }

    // gets information about the contents of text area
    var StatusEditor,
        $textarea = $form.find('textarea[name="message"]')
        .val('')
        .blur();

    // clears contents of text area
    if (StatusEditor = $textarea.data('XenForo.StatusEditor'))
    {
        StatusEditor.update();
    }

    // now replace the existing comments with the templateHtml that was returned
    $(ajaxData.templateHtml).xfInsert('replaceAll', '#mediaComments', 'xfShow');
});
Next, we need to alter your PHP to return the template.

I don't know the exact code you're running obviously, so this will be a basic guide that should be able to decipher.

Where you currently have this (or something similar) in your public controller:
PHP:
public function actionSaveComment()
{
	$data = $this->_input->filter(array(
		// some stuff
	));

	$writer = XenForo_DataWriter::create('JxCommentFeed_DataWriter_Comment');
	$writer->bulkSet($data);
	$writer->save();

	return $this->responseRedirect(
		XenForo_ControllerResponse_Redirect::SUCCESS,
		XenForo_Link::buildPublicLink('comment-feed')
	);
}
Try changing it to something like this:
PHP:
public function actionSaveComment()
{
	$data = $this->_input->filter(array(
		// some stuff
	));

	$writer = XenForo_DataWriter::create('JxCommentFeed_DataWriter_Comment');
	$writer->bulkSet($data);
	$writer->save();

	// XenForo AJAX calls always send an _xfNoRedirect parameter,
	// which allows us to detect if the request came from AJAX
	if ($this->_noRedirect())
	{
		$commentModel = $this->getModelFromCache('JxCommentFeed_Comment');

		$viewParams = array(
			'comments' => $commentModel->getLatestComments()
		);

		return $this->responseView(
			'JxCommentFeed_ViewPublic_LatestComments',
			'jxcommentfeed_latest_comments',
			$viewParams
		);
	}

	return $this->responseRedirect(
		XenForo_ControllerResponse_Redirect::SUCCESS,
		XenForo_Link::buildPublicLink('comment-feed')
	);
}
I hope that was reasonably clear... If not, take a look at actionComment() in XenForo_ControllerPublic_ProfilePost and see how it does a very similar thing around line 365.

Good luck!
 

Jaxel

Well-known member
I hope that was reasonably clear...

Good luck!
I do see one complication... You are replacing the ResponseRedirect with a ResponseView to get templateHtml. The problem is that my ResponseView was sending additional JSON parameters
Code:
		return $this->responseRedirect(
			XenForo_ControllerResponse_Redirect::SUCCESS,
			XenForo_Link::buildPublicLink('full:media', $media),
			null,
			array(
				'newurl' => XenForo_Link::buildPublicLink('full:media/comments', $media),
				'status' => new XenForo_Phrase('your_comment_has_been_posted')
				)
		);
How would I send those extra parameters 'newurl' and 'status' in ResponseView?
 

Kier

XenForo developer
Staff member
I do see one complication... You are replacing the ResponseRedirect with a ResponseView to get templateHtml. The problem is that my ResponseView was sending additional JSON parameters. How would I send those extra parameters 'newurl' and 'status' in ResponseView?
Video and demo code now uploading... all will become clear :)
 

Jaxel

Well-known member
Okay... here is an odd one for you...

OverlayTrigger is awesome, it does a popup overlay on click...

Is there any way I can get the overlay to popup on page load?
 

fos

Active member
This thread, or just the videos should be added to the help section so they can be found easily in the future.

Thanks, Jeff
 

Kier

XenForo developer
Staff member
Hey Kier, can I ask you exactly what "data-optInOut" does?
Let's say you have a form with four text boxes. The default XenForo.AutoValidator behaviour is to validate all those fields on blur, and individual fields have to expressly opt-out of the validation to prevent it from firing.

Sometimes, you have more fields that should not be inline-validated than those that should be, so you switch the behaviour from opt-out to opt-in, meaning that fields have to expressly opt-in to the validation process or they will be ignored and only validated on form submission.

Does that answer your question?
 
R

ragtek

Guest
data-optInOut prevents some fields from autovalidation.
You could check my invite add-on, there i'm using this;)

Edit: oh, kier was faster
 

x4rl

Well-known member
Kier is there a way to say "add <div class="secondaryContent"> " if only used in a overlay?
Am trying to get the register_form to work but as it has no background (in a overlay).
Or should I just make a new template and call that?

Cheers awesome video btw thanks alot
 

Kier

XenForo developer
Staff member
Kier is there a way to say "add <div class="secondaryContent"> " if only used in a overlay?
Am trying to get the register_form to work but as it has no background (in a overlay).
Or should I just make a new template and call that?

Cheers awesome video btw thanks alot
Try adding 'formOverlay' as a class to the register form.
 
Top