non form ajax... how to do it properly?

tenants

Well-known member
okay, so all of the ajax tutorials are about forms, and the classes you can use that make your life easier...

It works pretty well, but what if you don't want to submit a form

Lets say, a person visits a page, I then want to do some background js which calls an action (the background jobs shouldn't stop the page from loading and the user from using that page, so why make them wait!... a background job via ajax works for this)

I also want the response of that action

With forms, getting the sesponse is easy, but if you are not using xf forms, what should you do

here's an example of what I mean:


PHP:
<script>
$(document).ready(function() {
    var dataString = 'x={$x}' + '&_xfToken={$visitor.csrf_token_page}';
    $.ajax({
        type: "POST",
        url: "{xen:link something/someBackgroundJob, $data}",
        data: dataString,
        success: function(){}
    });
 
 
$('a#z').text('new text');
});
</script>

This kind of works, but I can't figure out how to get the response back

The BackgroundJob runs, for now I just send responseError('whatEver') for my response to actionSomeBackgroundJob

I would like to send something like:


return $this->responseRedirect(
XenForo_ControllerResponse_Redirect::SUCCESS,
dont redirect me!,
'Updated BackgroundJob',
array('sendThisBack' => $data['xyz'],)

);
but this wont work, since it redirects, so what should I use to get $data['xyz'] back ?


I could do this by creating a hidden form and then submitting that using form.submit... but it feels wrong? Is it, should I use a hidden form?
 
Your success function has no parameters? You could use XenForo.ajax for this, which is a wrapper for $.ajax, but with some defaults. In the callback you can receive the ajax data and text status. You could do:
Code:
XenForo.ajax(
    yourUrl,
    {}, // extra data to pass
    function(ajaxData, textStatus)
    {
    }
);
 
hmmm... I dont think that's the issues I'm having

The success function has no parameters since I haven't returned anything yet.. (I haven't added it, since I'm still returning wrong thing)

I need to be able to set the response of actionSomeBackgroundJob, without sending back the controllerResponse

so, I can do this:

Code:
<script>
$(document).ready(function() {
var dataString = 'update_visits={$updateVisits}' + '&_xfToken={$visitor.csrf_token_page}';
$.ajax({
type: "POST",
url: "{xen:link something/someBackgroundJob, $data}",
data: dataString,
success: function(returnedData){alert('got data 1' ) +returnedData;},
});
return false;
});
</script>

But if I use the following response type for my actionSomeBackgroundJob, I get the entire html with the controller response:

PHP:
return $this->responseRedirect(
XenForo_ControllerResponse_Redirect::SUCCESS,
null,
'Updated BackgroundJob',
array('sendThisBack' => $data['xyz'],)
);

This issue is, because I am in XenForo_ControllerPublic_Abstract, I always have to send back a coutrollerResonse,

even if I send back

PHP:
return $this->responseMessage($data['xyz']);

this still sends back a contollerResponse, but all I really want to do is send back
return $data['xyz']
But I can't do it from an action that extends XenForo_ControllerPublic_Abstract

I want to send back the minimum data (sending back the controller response is needless/bloaty for a background job)

[by the way, this is not something I should be doing with a cron job, it's a background job that happens only when a visitor visits a page and has to be done at that point]

I cant really put the background job in a model, since then I wont be able to access it via $.ajax({type: "POST"})
 
Hmm, in your first post you said you want the response of the action, but now you're saying you don't want the response? :confused:

As for returning the controller response, I don't think that should be too much of a problem if you've already made the request... What is this bloat you are referring to, do you have an example? With the responseMessage example above, the ajaxData should only have around 4 params. Although are you sure you even need to use ajax to do this at all? Your requirement is, "when a visitor visits a page and has to be done at that point". I noticed a update_visits param. If this is a visit counter, why not just increment the counter in the controller and pass the param you need along with the rest of the data? What is the data you need to return?
 
I do want the response, just not the html that comes with the XenForo_ControllerPublic_Abstract controllerResponse (This is basically a page, what you would see if you visited: some-background-job)

If this is a visit counter, why not just increment the counter in the controller and pass the param you need along with the rest of the data? What is the data you need to return?

It's not a visitor counter, it's a whole load of calculations to alter a factor within a search algorithum.. this includes "likes", tweets, "recommdations", content count, vistor count.. etc

It can't really be run as a cron (I have thought about it, but after a long hard think, it's not the route I want to go)
1) calling requests to twitter / facebook thousands of times via a cron within a few seconds is not going to be great (I know you can combine statments, but it's not need, see next point .. breaking this cron job up is also going to be messy)
2) It should only be run on pages recently visted (this will only be certain pages, not all of them, in fact for the ones that arent visited, it's ideal to not update the search algorithum factor, since lots of these pages get de-ranked if they arent visted regulary)
3) I want the people that visit the page to know that the job is run when they visit their page (there is a reason)

The idea is also to reduce any query count (reducing the page qurey count from about 17 to 12), and to make the page load faster. But at the same time, I can keep adding functionality (the jobs I do in the back ground for the page shouldn't affect the page load speed)

So.. I've been a bit naughty, for my actionSomeBackgroundJob, instead of sending back a controler reponse, I break out and the XenForo_ControllerPublic_Abstract, I dont return a controler resonse, I just
Code:
  echo $data['abc'];
        exit();

This seems to work, so now my above javacript gets the $data['abc'] response, and I can do what I wasnt with "returnedData"
 
I wasn't suggesting a cron, just to run the required code in the controller. For example in XF for thread views, they would just log the views in the controller. "calling requests to twitter / facebook thousands of times via a cron within a few seconds". Is that possible? :eek: After a cron is run once in XF it shouldn't rerun until the next period hits. Maybe you're using the term cron to refer to something else?

When you said you were getting the html output, I guess that is what you were referring to as bloat, it made me realise that you were still using $.ajax instead of XenForo.ajax and saw that you didn't set a dataType. It might be just as simple as setting the dataType: 'json'. So without explicitly setting the dataType to json you might end up with that HTML as the default. Like I said before, calling XenForo.ajax will set up some defaults for you, which includes setting the type to post and dataType to json. When returning a responseMessage you only see those 4 variables in your returned data instead of the HTML output you were seeing. Another nice thing about using XenForo.ajax is that it'll automatically update the alert and conversation counters.
 
Your success function has no parameters? You could use XenForo.ajax for this, which is a wrapper for $.ajax, but with some defaults. In the callback you can receive the ajax data and text status. You could do:
Code:
XenForo.ajax(
    yourUrl,
    {}, // extra data to pass
    function(ajaxData, textStatus)
    {
    }
);


oh you're absolutely bloody right, and it's very easy to use (I've used it lots before with forms, mind numbingly copying the tutorials)

but, if I just use this:

Code:
<script>
$(document).ready(function() {
        var myurl = "{xen:link something/someBackgroundJob, $data}";
        XenForo.ajax(myurl , {update_visits:{$updateVisits}}, function(ajaxData, textStatus)
        {
                $('a#rt').text(ajaxData.someParam);
        });
});
</script>

I just get the json back.. and no form required, cheers
 
I keep coming back to this post every now and then

Just in case I don't want to use the XenForo.ajax:.

To only get the json response, I need to add _xfResponseType to the sent data
To avoid the ajaxLoading overlay, I need to set global: false

Code:
<script>
       var sendData = {
           _xfResponseType: "json",
           _xfToken: "{$visitor.csrf_token_page}"
       };

       $.ajax({
           type: "POST",
           url: "{xen:link myplugin/here}",
           data: sendData,     
           global: false,
           dataType: "json",
           headers: {'X-Ajax-Referer': window.location.href},
           timeout: 30000, // 30s
           success: function (ajaxData, textStatus) {},
       });
</script>

The same with XenForo.ajax:
Code:
XenForo.ajax(
     {xen:link myplugin/bla},
     {someParam: someParam},
     function(ajaxData, textStatus){},
     {global: false, error: false}
);

Then I can still use the xenforo viewPublic response to send back only the relevant data:
Code:
<?php
class MyPlugin_ViewPublic_Here extends XenForo_ViewPublic_Base
{
    public function renderJson()
    {
        return XenForo_ViewRenderer_Json::jsonEncodeForOutput(array('myparam' => $this->_params['myparam']));
    }
}
 
Last edited:
Top Bottom