Jump to content

anybody could show an example of how to use $config->ajax ?


adrianmak
 Share

Recommended Posts

From processwire weekly #58, an article from a developer point of view, being said that, why he chose processwire over wordpress.

http://www.okeowoaderemi.com/articles/posts/wordpress-to-processwire-a-guide-for-developers/

When talking about ajax,  he said, "PW it as easy as just pointing an Ajax Call to a page and that's that"

if($config->ajax){

    //Run Code
    exit();
}else{

Normal HTTP Request

How can give me a explicit example of code, how to use $config->ajax for a ajax page call ?

Link to comment
Share on other sites

you can use it in several scenarios:

Progressive Enhancement of forms:

Return json for inline form validation (using the same url for the "good old form roundtrip action" and json_encoded responses:

$response = array(
	error => true,
	status => 'unsubmitted',
	msg => 'no valid form data given'
);

do {
	if ($_SERVER['REQUEST_METHOD'] != 'POST') break;

	$response['status'] = 'submitted';

	if(!$someValidator->validate($_POST)) break;

	// more validation logic here...

	$response['error'] = false;

} while (false);

if( $config->ajax ) {
	if (!headers_sent()) {
		header('Content-type: text/json');
		header('Content-type: application/json');
	}
        echo json_encode($response);
        return;
}

Rendering different templates when urls are accessed via ajax:

$template = $config->ajax ? "ui/projects_ajax.php" : "ui/projects.php";

$content = wireRenderFile( $template, array(
	"title"=>$title,
	"CategoryData"=>$pages->find("/categories/,include=hidden"),
	"PageData"=>$page
));

... we use this technique here (in combination with pushstate/history.js): http://www.accom.kg/ - If templates are accessed via ajax they are rendered without footer and header. This way we only load the necessary parts to be displayed. If the user (or google) visits the "real" page, navigation and footer are rendered.

Redirecting users that accidentally visit some api endpoint that should only be used via ajax:

if( !$config->ajax ) {
	$session->redirect('/');
}

// API-LOGIC HERE.

.... plus a billion other examples :)

  • Like 9
Link to comment
Share on other sites

That's my article, using Ajax is quite easy in PW, just make an Ajax call to your page, now the HTTP Header contains Ajax header in it, so $config->ajax will flag as true when it is an Ajax call and false if not, 

Do this

1. Make an Ajax Call to the Page

2. var_dump something if Ajax and exit and you will see your result

100% cleaner than WordPress and i stick to that statement, also thanks for reading my blog. If you have something you want me to write on please let me know, quite bored at home. 

  • Like 5
Link to comment
Share on other sites

A very simplified example. Reloading only the page content via ajax:

if( !$config->ajax ) include("head.inc");

echo $page->body;

if( !$config->ajax ) include("foot.inc");
  • Like 6
Link to comment
Share on other sites

I use the last example a lot in my work if the site is simple enough (only the content area changes and there nav stay and hold state). For a more complex site you may want to write some more logic but I try to keep Ajax and static page templates request as close as possible so as not to do double the work.

  • Like 1
Link to comment
Share on other sites

If you prefer some type of delayed output, you also can use both (regular and ajax) very close together:

$out = '';
$out .= {html head part};
$out .= {my menu content};
$out .= {some other content};

// her we come to the individual content
if ($config->ajax) $out = ''; // delete all collected output til here and start new

$out .= {my individual content};

//... collect until individual content is complete, then
if ($config->ajax) {
    echo $out;  // send it out as html
    exit();     // stop any further processing
}

// if it isn't a ajax call you collect also footer etc.
$out .= {my footer content};

// send out the complete html page
echo $out;
  • Like 4
Link to comment
Share on other sites

I use the last example a lot in my work if the site is simple enough (only the content area changes and there nav stay and hold state). For a more complex site you may want to write some more logic but I try to keep Ajax and static page templates request as close as possible so as not to do double the work.

In fact my example was very much simplified for this post. As we're using TemplateTwigReplace, we benefit from Twigs "extend" and "block" syntax. Regarding the Project named above there is one _base-template.twig that handles the "normal" output. It looks like this:

<!DOCTYPE html>
<html lang="de-DE" class="no-js">
	<head>

		{% include 'includes/htmlhead.twig' %}
		{% block htmlHead %}{% endblock htmlHead %}
	
	</head>
	<body data-module="ajaxcontent,fallback" class="js-template-{{ page.get('template')}}" itemscope itemtype="http://schema.org/WebPage">



		<div id="pt-main" class="pt-perspective">

			
			<div class="pt-page pt-page-current js-pt-main">
                                
                {{ page.renderChunk('chunks/header.twig', config.ajax ) }}

                {% block header %}{% endblock header %}

                <!-- #### MAIN CONTENT START #### -->
                <main role="main">

                    {% block mainContent %}{% endblock mainContent %}

                </main>
                <!-- #### MAIN CONTENT END #### -->

                {{ page.renderChunk( 'chunks/footer.twig', config.ajax ) }}

			</div>

			<!-- ADDITIONAL CONTENT WILL BE PLACED HERE. -->
			<div class="pt-page ajaxcontent js-ajaxcontent" id="ajaxcontent">
				<div class="ajaxcontent__inner">
					<div class="ajaxcontent__content js-ajaxcontent-content"></div>
				</div>
			</div>
			
			<!-- 2nd LEVEL ADDITIONAL CONTENT WILL BE PLACED HERE. -->
			<div class="pt-additional-content ajaxcontent js-ajaxcontent-lvl2" id="ajaxcontent-lvl2">
				<div class="ajaxcontent__inner">
					<div class="ajaxcontent__content js-ajaxcontent-lvl2-content"></div>
				</div>
			</div>
			
		</div>

		{% include 'includes/javascript.twig' %}
		{% block beforeBodyEnd %}{% endblock beforeBodyEnd %}

	</body>

</html>

basically it contains the html wrapper plus some blocks that can or cannot be filled with further content.

The _ajax-template.twig acts as a wrapper for pages that are displayed via ajax:

{% block header %}{{ page.renderChunk('chunks/header-ajax.twig') }}{% endblock header %}

{% block mainContent %}{% endblock mainContent %}

	
{# block footer %}{{ page.renderChunk( 'chunks/footer.twig', config.ajax ) }}{% endblock footer #}

As you can see it is missing all chrome and unneeded stuff plus it includes a special header (one without navigation elements other than a "close" button and the logo).

ALL pages extend those two default wrapper-templates and add their content to the respective blocks.

A (very simple) template for outputting pages like legal information with just a headline and content field would then look like this:

{% set extendsVar = config.ajax ?  '_ajax-template.twig' :  '_base-template.twig' %}

{% extends extendsVar %}

{% block mainContent %}
	<div class="row">
		<div class="small-12 columns editor">
			<h1 class="headline headline--stage">{{ page.get('headline|title') }}</h1>
			{{ page.content }}
		</div>
	</div>
{% endblock %}

... based on the config.ajax value the template chooses which layout file will be extended and then renders it's output to the mainContent area.

simple as that :)

  • Like 1
Link to comment
Share on other sites

If you prefer some type of delayed output, you also can use both (regular and ajax) very close together:

$out = '';
$out .= {html head part};
$out .= {my menu content};
$out .= {some other content};

// her we come to the individual content
if ($config->ajax) $out = ''; // delete all collected output til here and start new

$out .= {my individual content};

//... collect until individual content is complete, then
if ($config->ajax) {
    echo $out;  // send it out as html
    exit();     // stop any further processing
}

// if it isn't a ajax call you collect also footer etc.
$out .= {my footer content};

// send out the complete html page
echo $out;

I really loathe this "Strategy" it's not flexible and quite difficult to have logic in it, I prefer using this method, not sure what to call it

<?php
$Data=$pages->get("name=team-members");
$content=wireRenderFile("ui/about.php",array(
   "item"=>$page,
    "members"=>$Data->children()
));

it's highly flexible and you can have logic in it with ease and even swap out templates based on the condition.

  • Like 1
Link to comment
Share on other sites

That's my article, using Ajax is quite easy in PW, just make an Ajax call to your page, now the HTTP Header container an Ajax header in it, so $config->ajax will flag as true when it is an Ajax call and false if not, 

Do this

1. Make an Ajax Call to the Page

2. var_dump something if Ajax and exit and you will see your result

100% cleaner than WordPress and i stick to that statement, also thanks for reading my blog. If you have something you want me to write on please let me know, quite bored at home. 

How to make a ajax call in PW ? Let say

A page has a link to another page. In traditional, the link will bring user to that page directly.

If i want to make an ajax call to that page, the content of the targeted page will be shown on a div of the same page.

Link to comment
Share on other sites

In that page just use the $config->ajax and make a call to that page, in your jQuery ensure that in the success method, you display the content in whichever div you want ? I use Ajax in PW to upload images

Link to comment
Share on other sites

In that page just use the $config->ajax and make a call to that page, in your jQuery ensure that in the success method, you display the content in whichever div you want ? I use Ajax in PW to upload images

I could not understand how to make an ajax call to a page.

From your article, wordpress required wp_ajax action for a ajax call.

In PW, how to tell pw, the data being submitted is a ajax call ?

  • Like 1
Link to comment
Share on other sites

The request you don't do in pw, you do it in JavaScript. You'll have to study that part for yourself I'm afraid. Google ajax, have a look at the jquery ajax methods, read a book on javascript and so on.

Link to comment
Share on other sites

The request you don't do in pw, you do it in JavaScript. You'll have to study that part for yourself I'm afraid. Google ajax, have a look at the jquery ajax methods, read a book on javascript and so on.

I see. I knew how to do ajax in js/jquery.

I supposed "Making an ajax call in pw" is without using js. PW will take care of it by some kind of indicator, similar as of Drupal 7 form api

Link to comment
Share on other sites

I see. I knew how to do ajax in js/jquery.

I supposed "Making an ajax call in pw" is without using js. PW will take care of it by some kind of indicator, similar as of Drupal 7 form api

What have you done so far ?

Making an Ajax call is always on the frontend it has nothing to do with ProcessWire just make an Ajax call to your page it's that easy. try it first Ajax call in Processwire is nothing complicated.

Link to comment
Share on other sites

Just to clarify, AJAX in any CMS requires JavaScript. It cannot be done purely on the server side (PHP) as you have to get a request from the client side (your web browser) to tell the server what you want and listen for the response.

Any plugins or modules you have seen in other systems must also use JavaScript if they are doing AJAX - indeed the J in AJAX stands for JavaScript.

Link to comment
Share on other sites

  • 5 months later...

just in addition.

there is

return $this->halt();

now, to stop further output, but still let processwire shut down properly ;-)

Could this be used for example, if I don't want to use the "else" statement to render normal requests content, and just have it on the rest of the template file? 

Link to comment
Share on other sites

  • 2 years later...

Like adrianmak I am struggling to wrap my head around using ajax in Processwire. I actually already have some working ajax in my sites and have worked with ajax outside of Processwire in the past, but would still like to see a complete basic example for reference/reminder how to do this in Processwire.

diogo's example here is a good, stripped down start, but it is a bit frustrating to then be told we have to 'study [the javascript] part for yourself ... Google ajax, have a look at the jquery ajax methods, read a book on javascript and so on ...'. This stuff may all be completely obvious for developers who do this every day, but it is not for content developers or small business owners who have to figure this out once every few years.

This works fine as a basic ajax call demo without doing anything with config=>ajax:

Spoiler

<?php 

if($config->ajax) {
	
	echo 'Why does this not show up when the Ajax call is made?';
		
	return $this->halt();

} else {

include 'inc/head.php'; ?>

<body>

<div id="demo">
<h2>The XMLHttpRequest Object</h2>
<button type="button" onclick="loadDoc()">Change Content</button>
</div>

<?php include 'inc/footer.php'; 
}
?>

<script>
function loadDoc() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("demo").innerHTML =
      this.responseText;
    }
  };
  xhttp.open("GET", "../ajax_info.php", true);
  xhttp.send();
}
</script>

 

But I think it doesn't work if ajax_info.php is in a PW folder (?) and that is why it has to go via config->ajax. I have a working ajax script in my site with this:

if($config->ajax) {
	include 'inc/loadmore.php';
	
	return $this->halt();
}

And then the ajax call includes url parameters (?) that the loadmore.php can do someting with to send a result back.

What are the ways to send variables from the javascript to an external php process script in a PW folder and then back to the page?

Link to comment
Share on other sites

@modifiedcontent here you go with a very simple example using jQuery (but it's different for all javascript frameworks or vanilla javascript... I'm using the default profile for the example:

home.php

<?php namespace ProcessWire;
if($config->ajax) {
	$content = "content loaded via ajax @ " . date('d.m.Y H:i:s');
}
else {
	$content = $page->body . renderNav($page->children);
}

$sidebar = '<button id="loadrandom">load random page</button>';

_main.php: add this before your </head>

<script
  src="https://code.jquery.com/jquery-3.3.1.min.js"
  integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
  crossorigin="anonymous"></script>
<script>
  $(document).ready(function() {
    // add an event listener for the click event on #loadrandom button
    $('#loadrandom').click(function() {
      // check your console if everything works
      console.log('button was clicked');
      
      // use the load() method to replace the current content
      // of div#content by the content of div#content that is
      // returned from an ajax request to the current url ./
      $('#content').load('./ #content');
    });
  });
</script>

OjHmYb2.png

  • Like 5
Link to comment
Share on other sites

Thanks @bernhard, but this example assumes you use the default profile. I don't, so there is way too much unnecessary distracting stuff going on. I think this example only shows how you can fetch one line of text via an ajax call. Typically you'd want to send the call with parameters/variables (?) to a php script that does something with the vars and then returns something. I am looking for basic examples of that entire process.

I'll keep working on my example(s) above.

Link to comment
Share on other sites

11 hours ago, modifiedcontent said:

but this example assumes you use the default profile. I don't, so there is way too much unnecessary distracting stuff going on. I think this example only shows how you can fetch one line of text via an ajax call. Typically you'd want to send the call with parameters/variables (?) to a php script that does something with the vars and then returns something. I am looking for basic examples of that entire process.

It sounds to me as if your struggle is not with ProcessWire, but with JavaScript, specifically, JavaScript + Ajax, rather than ProcessWire + Ajax. It doesn't matter what profile is being used in ProcessWire. The only thing that $config->ajax does it to detect whether an Ajax call has been sent. It returns a Boolean; true if Ajax call made to the receiving 'file' (i.e. your template file or page) or false if not. Nothing more. The parameters you send with your Ajax call are up to you. The JS framework/library you use or vanilla JavaScript you use to make the Ajax call are up to you. ProcessWire will not care :-). 

An Ajax call will hit the server as either a GET or POST request, so you handle it accordingly.

The rules for what files/URL you can ping (I can't find the relevant posts at the moment) still apply. If you ping an ADMIN URL, ProcessWire will reject that get/post. If you ping a standalone php file within one of ProcessWire's protected folders, ProcessWire will reject that get/post. So, you can either send your request to the current page and let it include your standalone file or make your standalone file a template file of a template and ping a page that uses that template, etc.

Assuming you've sent your Ajax call to a valid 'url', you can handle things server-side like any other input. You validate and sanitize the data. If you have to send user input back to them, make sure you parse it through $sanitizer->entities(). I know you said you are frustrated by the 'Google-about-Ajax' suggestions, but I will tell you the same. A good tutorial/intro to Ajax would probably cost you about 30 minutes of your time :-). If you already have jQuery, use it to make life simpler (I know,... the JS purists here are groaning ;-)).

OK, to some quick example

if($config->ajax) {
    # 1. process input variables sent via Ajax
    $author = $sanitizer->text($input->author);// a parameter/variable 'author' was sent by ajax
    // validate $author here
    if(!$author) // error handling here
    //$email = $sanitizer->email($input->email);// just an example
    $volumes = (int) $input->volumes;// some integer input

    # 2. find requested books by the named author
    $books = $pages->find("template=book,name=$author,volumes>=$volumes,limit=20");
    
    $results = array();
    if($books->count) {
      foreach($books as $book) {
        $results[$book->id] = array('title'=>$book->title,'year'=>$book->year,'volumes'=>$book->volumes,'co_authors'=>$book->co_authors->explode('title'));
      }      
    }
    # 3. prepare output to send back as JSON response to Ajax call
    if(count($results)) $results['message'] = 'success';
    else $results['message'] = 'fail';
    
    # 4. send JSON output back to client browswer
    echo json_encode($results);
    exit;// or ProcessWire halt() if applicable
}
// no ajax
else {

}

You then handle the $results JSON in JavaScript, as you wish.

PS: written in browser and not tested.

 

  • Like 5
  • Thanks 1
Link to comment
Share on other sites

Quote

... It sounds to me as if your struggle is not with ProcessWire, but with JavaScript, specifically, JavaScript + Ajax ...

Yes, of course. I don't know Javascript. I have one bit of Ajax working in my PW site, but now want to step back and try to better understand how this stuff actually works. All examples help. Thanks kongondo.

Edit: Btw, I have the same problem with kongondo's latest example as with every other example of this; it only gives one part and assumes that the rest is obvious. kongondo's example is mostly generic PW PHP that has nothing to do with Ajax. The example says an 'author' var was sent by the Ajax call, but doesn't explain how - which is precisely what I am trying to wrap my head around. I am looking for an example that shows me how it all works together.

Here is a self-contained basic demo:

Spoiler

<?php 
if($config->ajax) {

	$variable = $_GET ['variable']; 
	
	echo 'I feel triggered by '. $variable;
	
	return $this->halt();

} else {

include 'inc/head.php'; ?>

<body>

<h2 id=demo>Let jQuery AJAX Change This Text</h2>

<button>Replace text by ajax call to same page</button>

<?php include 'inc/footer.php'; 
}
?>

<script>
var jAjax = jQuery.noConflict(); 
  
var sometext = "something dynamic";

jAjax(document).ready(function(){
    jAjax('button').click(function(){
        jAjax('#demo').load( '?variable='+encodeURIComponent(sometext) );
    });
});
</script>

 

 

Link to comment
Share on other sites

On 10/29/2018 at 9:00 PM, modifiedcontent said:

Edit: Btw, I have the same problem with kongondo's latest example as with every other example of this; it only gives one part and assumes that the rest is obvious. This example is mostly generic PW PHP that has nothing to do with Ajax. An 'author' var was sent by the Ajax call. How? I still don't see how it all works together.

If "the rest" is not obvious you have two options:

  • google
  • ask a specific question here in the forum

You are complaining that the examples suppose some kind of basic setup... But that's not a bad thing. That's just to have a common basis and to make sure all are talking about the same. If your setup is different, why don't you bring up a new installation and test things out the way several helpful and experienced people here in the forum where trying to explain? Maybe it has a reason why they do it how they do it?! Have you ever TRIED OUT one of the basic AJAX examples around the web?

What are you talking about in your basic demo? Does it work? Does it not work? What author var are you talking about? Nobody here knows anything about your setup. You never told about it in detail. If you just started with one of the shipped site profiles everybody would know what you are talking about and what would be going on. Once that is working and you understand how and why you can move on forward to customized setups.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...