Controller for a snippet

Hi, so i’ve managed to get a nice little PHP form with recaptcha 3 working, as a snippet to be reuseable on various pages.
Now i would love to add an ajax call to prevent the page reloading.
I have a script which prepares the data, then the ajaxmail.php controller which sends the email.
I have tried to use a controller “ajaxform.php”. but kirby didn’t recognize it as such.

How do i call a controller from a snippet?

My question leads to this piece of text:

xhr.open('POST', 'ajaxform.php');

I could use a special file directly in the domain directory, which works, but i really wanna use the kirby->email function, cause that is what cms is for

In my js

<script>
function process() {
  // (A) GET FORM DATA
  var data = new FormData();
  data.append('name', document.getElementById("name").value);
  data.append('email', document.getElementById("email").value);
  data.append('text', document.getElementById("text").value);

  // (B) AJAX
  var xhr = new XMLHttpRequest();
  
  xhr.open("POST", "https://mydomain/ajaxform.php");
  
  // What to do when server responds
  xhr.onload = function(){
    console.log(this.response);
	console.log('yay');
  };
  
  // Defining event listener for readystatechange event
  xhr.onreadystatechange = function() {
    // Check if the request is compete and was successful
    if(this.readyState === 4 && this.status === 200) {
        // Inserting the response from server into an HTML element
        document.getElementById("result").innerHTML = this.responseText;
        }
    };
  //xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  xhr.send(data);
 
  // (C) PREVENT HTML FORM SUBMIT
  return false;

}
</script>

I have tried to link it directly to the site.php which does not seem to work.
My question leads to this piece of text:

xhr.open('POST', 'ajaxform.php');

You can either do the form handling in a route or in a page controller, i.e. a dedicated page for form handling

Hi thanks, that is indeed my question.
My files are:
snippets/ajaxform.php with this code (simple, test one)

<script>
function process() {
  // (A) GET FORM DATA
  var data = new FormData();
  data.append('name', document.getElementById("name").value);
  data.append('email', document.getElementById("email").value);
  data.append('text', document.getElementById("text").value);

  // (B) AJAX
  var xhr = new XMLHttpRequest();
  
  xhr.open("POST", "site/controllers/sliderpage.php", true);
  
  // What to do when server responds
  xhr.onload = function(){
    console.log(this.response);
	console.log('yay');
  };
  
  // Defining event listener for readystatechange event
  xhr.onreadystatechange = function() {
    // Check if the request is compete and was successful
    if(this.readyState === 4 && this.status === 200) {
        // Inserting the response from server into an HTML element
        document.getElementById("result").innerHTML = this.responseText;
        }
    };
  xhr.send(data);
 
  // (C) PREVENT HTML FORM SUBMIT
  return false;

}

</script>

<div>
	<h2>Anfragen</h2>
	<h6>Hier kannst du was schreiben</h2>
</div>
<div id="result"></div>
<form onsubmit="return process()">
  Name: <input type="name" id="name" required><br>
  Email: <input type="email" id="email" required autofocus/><br>
  Message: <input type="text" id="text" required/><br>
  <input type="submit" name="submit" value="Absenden" class="g-recaptcha" 
			data-sitekey="reCAPTCHA_xyz" 
			data-callback='onSubmit' 
			data-action='submit'>
</form>

then, i have the controller code in
/controllers/pagenamewhereused.php

<?php
if($_SERVER["REQUEST_METHOD"] == "POST") {
    $name = htmlspecialchars(trim($_POST["name"]));
    $email = htmlspecialchars(trim($_POST["email"]));
	$text = htmlspecialchars(trim($_POST["text"]));
    
    // Check if form fields values are empty
    if(!empty($name)) {
        echo "<p>Hi, <b>$name</b>. Dein Zeugs wurde versendet.<p>";
        echo "<p>Deine Email: <b>$email</b></p>";
		echo "<p>Dein Text: <b>$text</b></p>";
    } else {
        echo "<p>NIXE</p>";
    }
} else {
    echo "<p>Something went wrong. Häng di auf.</p>";
}

?>

This is working so long as i hard-link it to https://domain/sliderpage.php
Can u please help me how to link/route it correctly to the site/controllers/pagenamewhereused.php ?
This:
xhr.open("POST", "site/controllers/sliderpage.php", true);

is giving me no results.
Thanks a lot!

I don’t really understand why this needs to ne handled by the pag where it is used if you are using the snippet on multiple pages.

In any case your form handling logic should not call a php script but a url, either the url of a page that hanles the backend part or a route

Hi, thanks for hanging in with me on saturday.
yeah, that is what i am thinking, just calling the url of the php script won’t work.
This is what i have tried:

xhr.open("POST", "https://mydomain.com/site/controllers/sliderpage.php", true); //or the https://.. long url
xhr.open("POST", "sliderpage.php", true); //when in controllers

where sliderpage.php is JUST the handler of the form.
I tried the same with

controllers/nameofsnippet.php 

didn’t work either. I think i am missing something important in the kirby logic.
Sry i am still new :slight_smile:

BUT - when i will put the php script directly to the main domain folder outside of kirby and call it with

xhr.open("POST", "https://mydomain.com/sliderpage.php", true);

then it is working fine, i just will have to set the smtp email sending by myself.
But it is not the kirby way and i would really like to use the kirby->email function.
how do i call an url of a controller from a snippet?

You know with ajax you have
1 - the snippet file with the form + the script which is sending the $data to
2 - a php controller, which is then sending the data back to page

I am failing in linking these 2 together in kirby logic

It’s too late tonight, but you are calling php scripts instead of a page url

i am trying to be calling the controller ^^
My code works if the php file with the controller code is outside of kirby system (domain root).
My question is how to tell the JS to call the controller php file with the code INSIDE the kirby system.
I hope you understand what i mean?

You cannot directly call the controller as php file. You have to pass the url to the page, e.g. something lile http://example.com/contact. When this page is called, the controller is automatically executed.

Calling php file indeed only works with files outside the Kirby system.

As I said, the alternative is to put the logic into a route and then call the pattern of this route.

For example, if you use a route like this:

'routes' => [
    [
      'pattern' => 'formhandler',
      'action'  => function () {
        // your formhandling logic
      }
    ],
  
   ],

You would call the url https://yourdomain.com/formhandler in your script.

Our formhandling logic is rather long and i would prefer not to put the php code in the config file, what is the best way to do this? With a custom controller? But how can we load it? And how to do this for multi language routes?

Routes can also be defined in a plugin (or in a file you include in the config).

Apart from that, the logic can be anywhere else (class, functions) and the be used inside the route.

1 Like

@pixelijn. Thank you. Could you give an example how to access in the config route my function? (Im not working with a plugin) Example i have the logic of all the forms in controllers/forms.php, forms does not exists as a page. I want to use the logic from the forms.php.

If the function is in a controller, it cannot be accessed without including the controller. I’d suggest you move the function to a plugin, ideally together with the route, so everything form related is together in one place.